about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.env.production.sample14
-rw-r--r--.ruby-version2
-rw-r--r--CHANGELOG.md233
-rw-r--r--Gemfile10
-rw-r--r--Gemfile.lock54
-rw-r--r--app.json9
-rw-r--r--app/controllers/about_controller.rb43
-rw-r--r--app/controllers/accounts_controller.rb1
-rw-r--r--app/controllers/activitypub/collections_controller.rb6
-rw-r--r--app/controllers/admin/relays_controller.rb7
-rw-r--r--app/controllers/admin/two_factor_authentications_controller.rb1
-rw-r--r--app/controllers/api/v1/accounts/statuses_controller.rb2
-rw-r--r--app/controllers/api/v1/accounts_controller.rb2
-rw-r--r--app/controllers/api/v2/search_controller.rb2
-rw-r--r--app/controllers/auth/challenges_controller.rb29
-rw-r--r--app/controllers/auth/sessions_controller.rb61
-rw-r--r--app/controllers/concerns/challengable_concern.rb65
-rw-r--r--app/controllers/concerns/export_controller_concern.rb7
-rw-r--r--app/controllers/custom_css_controller.rb1
-rw-r--r--app/controllers/directories_controller.rb2
-rw-r--r--app/controllers/follower_accounts_controller.rb1
-rw-r--r--app/controllers/following_accounts_controller.rb1
-rw-r--r--app/controllers/manifests_controller.rb1
-rw-r--r--app/controllers/media_controller.rb1
-rw-r--r--app/controllers/media_proxy_controller.rb1
-rw-r--r--app/controllers/remote_follow_controller.rb2
-rw-r--r--app/controllers/remote_interaction_controller.rb2
-rw-r--r--app/controllers/settings/aliases_controller.rb43
-rw-r--r--app/controllers/settings/exports_controller.rb7
-rw-r--r--app/controllers/settings/migration/redirects_controller.rb45
-rw-r--r--app/controllers/settings/migrations_controller.rb39
-rw-r--r--app/controllers/settings/two_factor_authentication/confirmations_controller.rb5
-rw-r--r--app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb6
-rw-r--r--app/controllers/settings/two_factor_authentications_controller.rb4
-rw-r--r--app/controllers/statuses_controller.rb1
-rw-r--r--app/controllers/tags_controller.rb2
-rw-r--r--app/controllers/well_known/nodeinfo_controller.rb19
-rw-r--r--app/helpers/settings_helper.rb8
-rw-r--r--app/javascript/flavours/glitch/actions/blocks.js14
-rw-r--r--app/javascript/flavours/glitch/actions/compose.js5
-rw-r--r--app/javascript/flavours/glitch/actions/conversations.js28
-rw-r--r--app/javascript/flavours/glitch/actions/importer/normalizer.js3
-rw-r--r--app/javascript/flavours/glitch/components/avatar_composite.js28
-rw-r--r--app/javascript/flavours/glitch/components/column_back_button_slim.js2
-rw-r--r--app/javascript/flavours/glitch/components/poll.js27
-rw-r--r--app/javascript/flavours/glitch/containers/status_container.js17
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js15
-rw-r--r--app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js157
-rw-r--r--app/javascript/flavours/glitch/features/direct_timeline/containers/conversation_container.js75
-rw-r--r--app/javascript/flavours/glitch/features/favourites/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/followers/index.js6
-rw-r--r--app/javascript/flavours/glitch/features/following/index.js6
-rw-r--r--app/javascript/flavours/glitch/features/getting_started/index.js8
-rw-r--r--app/javascript/flavours/glitch/features/notifications/components/filter_bar.js2
-rw-r--r--app/javascript/flavours/glitch/features/reblogs/index.js4
-rw-r--r--app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js18
-rw-r--r--app/javascript/flavours/glitch/features/status/index.js20
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/block_modal.js103
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js12
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/modal_root.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/mute_modal.js15
-rw-r--r--app/javascript/flavours/glitch/packs/public.js10
-rw-r--r--app/javascript/flavours/glitch/packs/settings.js20
-rw-r--r--app/javascript/flavours/glitch/reducers/blocks.js22
-rw-r--r--app/javascript/flavours/glitch/reducers/compose.js7
-rw-r--r--app/javascript/flavours/glitch/reducers/index.js2
-rw-r--r--app/javascript/flavours/glitch/reducers/mutes.js2
-rw-r--r--app/javascript/flavours/glitch/reducers/notifications.js4
-rw-r--r--app/javascript/flavours/glitch/reducers/timelines.js5
-rw-r--r--app/javascript/flavours/glitch/styles/_mixins.scss18
-rw-r--r--app/javascript/flavours/glitch/styles/about.scss179
-rw-r--r--app/javascript/flavours/glitch/styles/admin.scss199
-rw-r--r--app/javascript/flavours/glitch/styles/basics.scss3
-rw-r--r--app/javascript/flavours/glitch/styles/components/accounts.scss36
-rw-r--r--app/javascript/flavours/glitch/styles/components/composer.scss8
-rw-r--r--app/javascript/flavours/glitch/styles/components/index.scss83
-rw-r--r--app/javascript/flavours/glitch/styles/components/modal.scss73
-rw-r--r--app/javascript/flavours/glitch/styles/components/search.scss22
-rw-r--r--app/javascript/flavours/glitch/styles/components/status.scss1
-rw-r--r--app/javascript/flavours/glitch/styles/containers.scss62
-rw-r--r--app/javascript/flavours/glitch/styles/forms.scss15
-rw-r--r--app/javascript/flavours/glitch/styles/mastodon-light/diff.scss2
-rw-r--r--app/javascript/flavours/glitch/styles/polls.scss10
-rw-r--r--app/javascript/flavours/glitch/styles/tables.scss67
-rw-r--r--app/javascript/flavours/glitch/styles/widgets.scss83
-rw-r--r--app/javascript/flavours/glitch/theme.yml2
-rw-r--r--app/javascript/flavours/glitch/util/async-components.js4
-rw-r--r--app/javascript/flavours/glitch/util/emoji/index.js2
-rw-r--r--app/javascript/mastodon/actions/blocks.js14
-rw-r--r--app/javascript/mastodon/actions/compose.js6
-rw-r--r--app/javascript/mastodon/actions/conversations.js28
-rw-r--r--app/javascript/mastodon/actions/importer/normalizer.js3
-rw-r--r--app/javascript/mastodon/actions/notifications.js11
-rw-r--r--app/javascript/mastodon/components/avatar_composite.js28
-rw-r--r--app/javascript/mastodon/components/column_header.js4
-rw-r--r--app/javascript/mastodon/components/poll.js27
-rw-r--r--app/javascript/mastodon/components/scrollable_list.js1
-rw-r--r--app/javascript/mastodon/containers/media_container.js16
-rw-r--r--app/javascript/mastodon/containers/status_container.js19
-rw-r--r--app/javascript/mastodon/features/account_timeline/containers/header_container.js15
-rw-r--r--app/javascript/mastodon/features/direct_timeline/components/conversation.js128
-rw-r--r--app/javascript/mastodon/features/direct_timeline/containers/conversation_container.js75
-rw-r--r--app/javascript/mastodon/features/emoji/emoji.js2
-rw-r--r--app/javascript/mastodon/features/favourites/index.js4
-rw-r--r--app/javascript/mastodon/features/followers/index.js6
-rw-r--r--app/javascript/mastodon/features/following/index.js6
-rw-r--r--app/javascript/mastodon/features/getting_started/index.js8
-rw-r--r--app/javascript/mastodon/features/notifications/components/filter_bar.js2
-rw-r--r--app/javascript/mastodon/features/notifications/index.js7
-rw-r--r--app/javascript/mastodon/features/reblogs/index.js4
-rw-r--r--app/javascript/mastodon/features/status/containers/detailed_status_container.js18
-rw-r--r--app/javascript/mastodon/features/status/index.js20
-rw-r--r--app/javascript/mastodon/features/ui/components/block_modal.js103
-rw-r--r--app/javascript/mastodon/features/ui/components/focal_point_modal.js12
-rw-r--r--app/javascript/mastodon/features/ui/components/modal_root.js27
-rw-r--r--app/javascript/mastodon/features/ui/components/mute_modal.js15
-rw-r--r--app/javascript/mastodon/features/ui/util/async-components.js4
-rw-r--r--app/javascript/mastodon/locales/ar.json33
-rw-r--r--app/javascript/mastodon/locales/ast.json5
-rw-r--r--app/javascript/mastodon/locales/bg.json19
-rw-r--r--app/javascript/mastodon/locales/bn.json5
-rw-r--r--app/javascript/mastodon/locales/br.json95
-rw-r--r--app/javascript/mastodon/locales/ca.json5
-rw-r--r--app/javascript/mastodon/locales/co.json11
-rw-r--r--app/javascript/mastodon/locales/cs.json9
-rw-r--r--app/javascript/mastodon/locales/cy.json61
-rw-r--r--app/javascript/mastodon/locales/da.json5
-rw-r--r--app/javascript/mastodon/locales/de.json11
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json55
-rw-r--r--app/javascript/mastodon/locales/el.json17
-rw-r--r--app/javascript/mastodon/locales/en.json5
-rw-r--r--app/javascript/mastodon/locales/eo.json65
-rw-r--r--app/javascript/mastodon/locales/es-AR.json419
-rw-r--r--app/javascript/mastodon/locales/es.json15
-rw-r--r--app/javascript/mastodon/locales/et.json5
-rw-r--r--app/javascript/mastodon/locales/eu.json5
-rw-r--r--app/javascript/mastodon/locales/fa.json37
-rw-r--r--app/javascript/mastodon/locales/fi.json5
-rw-r--r--app/javascript/mastodon/locales/fr.json33
-rw-r--r--app/javascript/mastodon/locales/ga.json420
-rw-r--r--app/javascript/mastodon/locales/gl.json9
-rw-r--r--app/javascript/mastodon/locales/he.json5
-rw-r--r--app/javascript/mastodon/locales/hi.json5
-rw-r--r--app/javascript/mastodon/locales/hr.json5
-rw-r--r--app/javascript/mastodon/locales/hu.json57
-rw-r--r--app/javascript/mastodon/locales/hy.json5
-rw-r--r--app/javascript/mastodon/locales/id.json5
-rw-r--r--app/javascript/mastodon/locales/io.json5
-rw-r--r--app/javascript/mastodon/locales/it.json29
-rw-r--r--app/javascript/mastodon/locales/ja.json21
-rw-r--r--app/javascript/mastodon/locales/ka.json5
-rw-r--r--app/javascript/mastodon/locales/kk.json5
-rw-r--r--app/javascript/mastodon/locales/ko.json11
-rw-r--r--app/javascript/mastodon/locales/lt.json5
-rw-r--r--app/javascript/mastodon/locales/lv.json5
-rw-r--r--app/javascript/mastodon/locales/ms.json5
-rw-r--r--app/javascript/mastodon/locales/nl.json33
-rw-r--r--app/javascript/mastodon/locales/nn.json15
-rw-r--r--app/javascript/mastodon/locales/no.json5
-rw-r--r--app/javascript/mastodon/locales/oc.json57
-rw-r--r--app/javascript/mastodon/locales/pl.json11
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json51
-rw-r--r--app/javascript/mastodon/locales/pt-PT.json5
-rw-r--r--app/javascript/mastodon/locales/ro.json5
-rw-r--r--app/javascript/mastodon/locales/ru.json5
-rw-r--r--app/javascript/mastodon/locales/sk.json11
-rw-r--r--app/javascript/mastodon/locales/sl.json5
-rw-r--r--app/javascript/mastodon/locales/sq.json5
-rw-r--r--app/javascript/mastodon/locales/sr-Latn.json5
-rw-r--r--app/javascript/mastodon/locales/sr.json5
-rw-r--r--app/javascript/mastodon/locales/sv.json5
-rw-r--r--app/javascript/mastodon/locales/ta.json5
-rw-r--r--app/javascript/mastodon/locales/te.json5
-rw-r--r--app/javascript/mastodon/locales/th.json13
-rw-r--r--app/javascript/mastodon/locales/tr.json5
-rw-r--r--app/javascript/mastodon/locales/uk.json5
-rw-r--r--app/javascript/mastodon/locales/whitelist_es-AR.json2
-rw-r--r--app/javascript/mastodon/locales/whitelist_ga.json2
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json5
-rw-r--r--app/javascript/mastodon/locales/zh-HK.json5
-rw-r--r--app/javascript/mastodon/locales/zh-TW.json5
-rw-r--r--app/javascript/mastodon/reducers/blocks.js22
-rw-r--r--app/javascript/mastodon/reducers/compose.js7
-rw-r--r--app/javascript/mastodon/reducers/index.js2
-rw-r--r--app/javascript/mastodon/reducers/mutes.js2
-rw-r--r--app/javascript/mastodon/reducers/notifications.js11
-rw-r--r--app/javascript/mastodon/reducers/timelines.js5
-rw-r--r--app/javascript/mastodon/utils/scrollbar.js36
-rw-r--r--app/javascript/packs/public.js10
-rw-r--r--app/javascript/styles/mastodon-light/diff.scss2
-rw-r--r--app/javascript/styles/mastodon/_mixins.scss18
-rw-r--r--app/javascript/styles/mastodon/about.scss179
-rw-r--r--app/javascript/styles/mastodon/admin.scss181
-rw-r--r--app/javascript/styles/mastodon/basics.scss3
-rw-r--r--app/javascript/styles/mastodon/components.scss219
-rw-r--r--app/javascript/styles/mastodon/containers.scss62
-rw-r--r--app/javascript/styles/mastodon/forms.scss8
-rw-r--r--app/javascript/styles/mastodon/polls.scss10
-rw-r--r--app/javascript/styles/mastodon/tables.scss67
-rw-r--r--app/javascript/styles/mastodon/widgets.scss83
-rw-r--r--app/lib/activity_tracker.rb2
-rw-r--r--app/lib/activitypub/activity/create.rb40
-rw-r--r--app/lib/activitypub/activity/follow.rb2
-rw-r--r--app/lib/activitypub/activity/move.rb6
-rw-r--r--app/lib/activitypub/adapter.rb1
-rw-r--r--app/lib/nodeinfo/adapter.rb7
-rw-r--r--app/lib/toc_generator.rb69
-rw-r--r--app/mailers/user_mailer.rb33
-rw-r--r--app/models/account_alias.rb47
-rw-r--r--app/models/account_migration.rb78
-rw-r--r--app/models/concerns/account_associations.rb2
-rw-r--r--app/models/concerns/ldap_authenticable.rb44
-rw-r--r--app/models/domain_block.rb1
-rw-r--r--app/models/form/challenge.rb8
-rw-r--r--app/models/form/migration.rb25
-rw-r--r--app/models/form/redirect.rb47
-rw-r--r--app/models/poll.rb5
-rw-r--r--app/models/preview_card.rb4
-rw-r--r--app/models/relay.rb5
-rw-r--r--app/models/remote_follow.rb2
-rw-r--r--app/models/status.rb2
-rw-r--r--app/models/tag.rb13
-rw-r--r--app/models/user.rb11
-rw-r--r--app/models/web/push_subscription.rb4
-rw-r--r--app/presenters/instance_presenter.rb4
-rw-r--r--app/serializers/activitypub/move_serializer.rb26
-rw-r--r--app/serializers/activitypub/note_serializer.rb12
-rw-r--r--app/serializers/nodeinfo/discovery_serializer.rb11
-rw-r--r--app/serializers/nodeinfo/serializer.rb41
-rw-r--r--app/serializers/rest/credential_account_serializer.rb1
-rw-r--r--app/serializers/rest/poll_serializer.rb7
-rw-r--r--app/serializers/rss/account_serializer.rb2
-rw-r--r--app/serializers/rss/tag_serializer.rb2
-rw-r--r--app/services/account_search_service.rb10
-rw-r--r--app/services/activitypub/process_poll_service.rb5
-rw-r--r--app/services/fetch_link_card_service.rb2
-rw-r--r--app/services/follow_service.rb2
-rw-r--r--app/services/move_service.rb32
-rw-r--r--app/services/post_status_service.rb2
-rw-r--r--app/services/search_service.rb3
-rw-r--r--app/services/tag_search_service.rb29
-rw-r--r--app/services/update_account_service.rb4
-rw-r--r--app/services/vote_service.rb32
-rw-r--r--app/views/about/_domain_blocks.html.haml10
-rw-r--r--app/views/about/blocks.html.haml48
-rw-r--r--app/views/about/more.html.haml55
-rw-r--r--app/views/admin/dashboard/index.html.haml24
-rw-r--r--app/views/admin/tags/index.html.haml8
-rw-r--r--app/views/auth/challenges/new.html.haml15
-rw-r--r--app/views/auth/registrations/_status.html.haml30
-rw-r--r--app/views/auth/registrations/edit.html.haml13
-rw-r--r--app/views/auth/shared/_links.html.haml2
-rw-r--r--app/views/layouts/admin.html.haml20
-rw-r--r--app/views/settings/aliases/index.html.haml29
-rw-r--r--app/views/settings/exports/show.html.haml4
-rw-r--r--app/views/settings/migration/redirects/new.html.haml27
-rw-r--r--app/views/settings/migrations/show.html.haml88
-rw-r--r--app/views/settings/profiles/show.html.haml5
-rw-r--r--app/views/settings/two_factor_authentications/show.html.haml38
-rw-r--r--app/views/statuses/_poll.html.haml16
-rw-r--r--app/views/user_mailer/two_factor_disabled.html.haml43
-rw-r--r--app/views/user_mailer/two_factor_disabled.text.erb7
-rw-r--r--app/views/user_mailer/two_factor_enabled.html.haml43
-rw-r--r--app/views/user_mailer/two_factor_enabled.text.erb7
-rw-r--r--app/views/user_mailer/two_factor_recovery_codes_changed.html.haml43
-rw-r--r--app/views/user_mailer/two_factor_recovery_codes_changed.text.erb7
-rw-r--r--app/workers/activitypub/move_distribution_worker.rb33
-rw-r--r--app/workers/move_worker.rb33
-rw-r--r--config/application.rb3
-rw-r--r--config/initializers/devise.rb11
-rw-r--r--config/initializers/health_check.rb2
-rw-r--r--config/initializers/inflections.rb1
-rw-r--r--config/initializers/paperclip.rb1
-rw-r--r--config/locales/activerecord.br.yml12
-rw-r--r--config/locales/activerecord.es.yml18
-rw-r--r--config/locales/ar.yml73
-rw-r--r--config/locales/ast.yml4
-rw-r--r--config/locales/bn.yml3
-rw-r--r--config/locales/ca.yml23
-rw-r--r--config/locales/co.yml81
-rw-r--r--config/locales/cs.yml85
-rw-r--r--config/locales/cy.yml82
-rw-r--r--config/locales/da.yml8
-rw-r--r--config/locales/de.yml81
-rw-r--r--config/locales/devise.ar.yml4
-rw-r--r--config/locales/devise.br.yml32
-rw-r--r--config/locales/devise.co.yml12
-rw-r--r--config/locales/devise.cs.yml12
-rw-r--r--config/locales/devise.cy.yml12
-rw-r--r--config/locales/devise.de.yml12
-rw-r--r--config/locales/devise.el.yml6
-rw-r--r--config/locales/devise.en.yml12
-rw-r--r--config/locales/devise.es.yml87
-rw-r--r--config/locales/devise.fa.yml12
-rw-r--r--config/locales/devise.fr.yml12
-rw-r--r--config/locales/devise.gl.yml12
-rw-r--r--config/locales/devise.hu.yml12
-rw-r--r--config/locales/devise.it.yml11
-rw-r--r--config/locales/devise.ja.yml12
-rw-r--r--config/locales/devise.ko.yml12
-rw-r--r--config/locales/devise.nl.yml12
-rw-r--r--config/locales/devise.oc.yml12
-rw-r--r--config/locales/devise.pt-PT.yml83
-rw-r--r--config/locales/devise.sk.yml2
-rw-r--r--config/locales/doorkeeper.ar.yml2
-rw-r--r--config/locales/doorkeeper.es-AR.yml1
-rw-r--r--config/locales/el.yml54
-rw-r--r--config/locales/en.yml83
-rw-r--r--config/locales/eo.yml34
-rw-r--r--config/locales/es-AR.yml20
-rw-r--r--config/locales/es.yml27
-rw-r--r--config/locales/et.yml6
-rw-r--r--config/locales/eu.yml10
-rw-r--r--config/locales/fa.yml103
-rw-r--r--config/locales/fi.yml6
-rw-r--r--config/locales/fr.yml96
-rw-r--r--config/locales/gl.yml77
-rw-r--r--config/locales/he.yml3
-rw-r--r--config/locales/hu.yml100
-rw-r--r--config/locales/id.yml3
-rw-r--r--config/locales/it.yml48
-rw-r--r--config/locales/ja.yml102
-rw-r--r--config/locales/ka.yml6
-rw-r--r--config/locales/kk.yml6
-rw-r--r--config/locales/ko.yml102
-rw-r--r--config/locales/lt.yml6
-rw-r--r--config/locales/ms.yml3
-rw-r--r--config/locales/nl.yml138
-rw-r--r--config/locales/no.yml6
-rw-r--r--config/locales/oc.yml89
-rw-r--r--config/locales/pl.yml6
-rw-r--r--config/locales/pt-BR.yml130
-rw-r--r--config/locales/pt-PT.yml6
-rw-r--r--config/locales/ru.yml8
-rw-r--r--config/locales/simple_form.ar.yml15
-rw-r--r--config/locales/simple_form.co.yml14
-rw-r--r--config/locales/simple_form.cs.yml16
-rw-r--r--config/locales/simple_form.cy.yml30
-rw-r--r--config/locales/simple_form.de.yml14
-rw-r--r--config/locales/simple_form.el.yml12
-rw-r--r--config/locales/simple_form.en.yml12
-rw-r--r--config/locales/simple_form.es-AR.yml1
-rw-r--r--config/locales/simple_form.es.yml14
-rw-r--r--config/locales/simple_form.fa.yml28
-rw-r--r--config/locales/simple_form.fr.yml14
-rw-r--r--config/locales/simple_form.gl.yml14
-rw-r--r--config/locales/simple_form.hu.yml18
-rw-r--r--config/locales/simple_form.ja.yml14
-rw-r--r--config/locales/simple_form.ko.yml18
-rw-r--r--config/locales/simple_form.nl.yml29
-rw-r--r--config/locales/simple_form.oc.yml27
-rw-r--r--config/locales/simple_form.pt-BR.yml27
-rw-r--r--config/locales/simple_form.pt-PT.yml6
-rw-r--r--config/locales/simple_form.th.yml2
-rw-r--r--config/locales/simple_form.uk.yml1
-rw-r--r--config/locales/sk.yml57
-rw-r--r--config/locales/sl.yml6
-rw-r--r--config/locales/sq.yml6
-rw-r--r--config/locales/sr-Latn.yml6
-rw-r--r--config/locales/sr.yml6
-rw-r--r--config/locales/sv.yml6
-rw-r--r--config/locales/te.yml3
-rw-r--r--config/locales/th.yml18
-rw-r--r--config/locales/tr.yml15
-rw-r--r--config/locales/uk.yml17
-rw-r--r--config/locales/zh-CN.yml10
-rw-r--r--config/locales/zh-HK.yml6
-rw-r--r--config/locales/zh-TW.yml6
-rw-r--r--config/navigation.rb10
-rw-r--r--config/routes.rb12
-rw-r--r--db/migrate/20161202132159_add_in_reply_to_account_id_to_statuses.rb2
-rw-r--r--db/migrate/20170209184350_add_reply_to_statuses.rb2
-rw-r--r--db/migrate/20190914202517_create_account_migrations.rb12
-rw-r--r--db/migrate/20190915194355_create_account_aliases.rb11
-rw-r--r--db/migrate/20190927232842_add_voters_count_to_polls.rb5
-rw-r--r--db/post_migrate/20190927124642_remove_invalid_web_push_subscription.rb18
-rw-r--r--db/schema.rb26
-rw-r--r--lib/devise/ldap_authenticatable.rb55
-rw-r--r--lib/devise/two_factor_ldap_authenticatable.rb32
-rw-r--r--lib/devise/two_factor_pam_authenticatable.rb31
-rw-r--r--lib/mastodon/version.rb8
-rw-r--r--lib/tasks/mastodon.rake30
-rw-r--r--package.json10
-rw-r--r--scalingo.json9
-rw-r--r--spec/controllers/auth/challenges_controller_spec.rb46
-rw-r--r--spec/controllers/auth/sessions_controller_spec.rb2
-rw-r--r--spec/controllers/concerns/challengable_concern_spec.rb114
-rw-r--r--spec/controllers/settings/migrations_controller_spec.rb14
-rw-r--r--spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb10
-rw-r--r--spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb2
-rw-r--r--spec/controllers/settings/two_factor_authentications_controller_spec.rb2
-rw-r--r--spec/controllers/well_known/nodeinfo_controller_spec.rb36
-rw-r--r--spec/fabricators/account_alias_fabricator.rb5
-rw-r--r--spec/fabricators/account_migration_fabricator.rb6
-rw-r--r--spec/lib/activitypub/activity/follow_spec.rb30
-rw-r--r--spec/mailers/previews/user_mailer_preview.rb15
-rw-r--r--spec/models/account_alias_spec.rb5
-rw-r--r--spec/models/account_migration_spec.rb5
-rw-r--r--spec/services/follow_service_spec.rb27
-rw-r--r--spec/services/search_service_spec.rb4
-rw-r--r--spec/services/update_account_service_spec.rb38
-rw-r--r--yarn.lock720
402 files changed, 8236 insertions, 2677 deletions
diff --git a/.env.production.sample b/.env.production.sample
index 2fbecc91a..417e91528 100644
--- a/.env.production.sample
+++ b/.env.production.sample
@@ -115,6 +115,20 @@ SMTP_FROM_ADDRESS=notifications@example.com
 # S3_ENDPOINT=
 # S3_SIGNATURE_VERSION=
 
+# Google Cloud Storage (optional)
+# Use S3 compatible API. Since GCS does not support Multipart Upload,
+# increase the value of S3_MULTIPART_THRESHOLD to disable Multipart Upload.
+# The attachment host must allow cross origin request - see the description
+# above.
+# S3_ENABLED=true
+# AWS_ACCESS_KEY_ID=
+# AWS_SECRET_ACCESS_KEY=
+# S3_REGION=
+# S3_PROTOCOL=https
+# S3_HOSTNAME=storage.googleapis.com
+# S3_ENDPOINT=https://storage.googleapis.com
+# S3_MULTIPART_THRESHOLD=52428801 # 50.megabytes
+
 # Swift (optional)
 # The attachment host must allow cross origin request - see the description
 # above.
diff --git a/.ruby-version b/.ruby-version
index 6a6a3d8e3..2714f5313 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.6.1
+2.6.4
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 539fec531..4e9ccdc8c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,239 @@ Changelog
 
 All notable changes to this project will be documented in this file.
 
+## Unreleased
+
+### Added
+
+- Add "not available" label to unloaded media attachments in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11715), [Gargron](https://github.com/tootsuite/mastodon/pull/11745))
+- **Add profile directory to web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11688), [mayaeh](https://github.com/tootsuite/mastodon/pull/11872))
+  - Add profile directory opt-in federation
+  - Add profile directory REST API
+- Add special alert for throttled requests in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11677))
+- Add confirmation modal when logging out from the web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11671))
+- **Add audio player in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11644), [Gargron](https://github.com/tootsuite/mastodon/pull/11652), [Gargron](https://github.com/tootsuite/mastodon/pull/11654), [ThibG](https://github.com/tootsuite/mastodon/pull/11629))
+- **Add autosuggestions for hashtags in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11422), [ThibG](https://github.com/tootsuite/mastodon/pull/11632), [Gargron](https://github.com/tootsuite/mastodon/pull/11764), [Gargron](https://github.com/tootsuite/mastodon/pull/11588), [Gargron](https://github.com/tootsuite/mastodon/pull/11442))
+- **Add media editing modal with OCR tool in web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11563), [Gargron](https://github.com/tootsuite/mastodon/pull/11566), [ThibG](https://github.com/tootsuite/mastodon/pull/11575), [ThibG](https://github.com/tootsuite/mastodon/pull/11576), [Gargron](https://github.com/tootsuite/mastodon/pull/11577), [Gargron](https://github.com/tootsuite/mastodon/pull/11573), [Gargron](https://github.com/tootsuite/mastodon/pull/11571))
+- Add indicator of unread notifications to window title when web UI is out of focus ([Gargron](https://github.com/tootsuite/mastodon/pull/11560), [Gargron](https://github.com/tootsuite/mastodon/pull/11572))
+- Add indicator for which options you voted for in a poll in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11195))
+- **Add search results pagination to web UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11409), [ThibG](https://github.com/tootsuite/mastodon/pull/11447))
+- **Add option to disable real-time updates in web UI ("slow mode")** ([Gargron](https://github.com/tootsuite/mastodon/pull/9984), [ykzts](https://github.com/tootsuite/mastodon/pull/11880), [ThibG](https://github.com/tootsuite/mastodon/pull/11883), [Gargron](https://github.com/tootsuite/mastodon/pull/11898), [ThibG](https://github.com/tootsuite/mastodon/pull/11859))
+- Add option to disable blurhash previews in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11188))
+- Add native smooth scrolling when supported in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11207))
+- Add search and sort functions to hashtag admin UI ([mayaeh](https://github.com/tootsuite/mastodon/pull/11829), [Gargron](https://github.com/tootsuite/mastodon/pull/11897), [mayaeh](https://github.com/tootsuite/mastodon/pull/11875))
+- Add setting for default search engine indexing in admin UI ([brortao](https://github.com/tootsuite/mastodon/pull/11804))
+- Add account bio to account view in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11473))
+- **Add option to include reported statuses in warning e-mail from admin UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11639), [Gargron](https://github.com/tootsuite/mastodon/pull/11812), [Gargron](https://github.com/tootsuite/mastodon/pull/11741), [Gargron](https://github.com/tootsuite/mastodon/pull/11698), [mayaeh](https://github.com/tootsuite/mastodon/pull/11765))
+- Add number of pending accounts and pending hashtags to dashboard in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11514))
+- **Add account migration UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11846), [noellabo](https://github.com/tootsuite/mastodon/pull/11905), [noellabo](https://github.com/tootsuite/mastodon/pull/11907), [noellabo](https://github.com/tootsuite/mastodon/pull/11906), [noellabo](https://github.com/tootsuite/mastodon/pull/11902))
+- **Add table of contents to about page** ([Gargron](https://github.com/tootsuite/mastodon/pull/11885), [ykzts](https://github.com/tootsuite/mastodon/pull/11941), [ykzts](https://github.com/tootsuite/mastodon/pull/11895), [Kjwon15](https://github.com/tootsuite/mastodon/pull/11916))
+- **Add password challenge to 2FA settings, e-mail notifications** ([Gargron](https://github.com/tootsuite/mastodon/pull/11878))
+- Add optional invite comments ([ThibG](https://github.com/tootsuite/mastodon/pull/10465))
+- **Add optional public list of domain blocks with comments** ([ThibG](https://github.com/tootsuite/mastodon/pull/11298), [ThibG](https://github.com/tootsuite/mastodon/pull/11515), [Gargron](https://github.com/tootsuite/mastodon/pull/11908))
+- Add an RSS feed for featured hashtags ([noellabo](https://github.com/tootsuite/mastodon/pull/10502))
+- Add explanations to featured hashtags UI and profile ([Gargron](https://github.com/tootsuite/mastodon/pull/11586))
+- **Add hashtag trends with admin and user settings** ([Gargron](https://github.com/tootsuite/mastodon/pull/11490), [Gargron](https://github.com/tootsuite/mastodon/pull/11502), [Gargron](https://github.com/tootsuite/mastodon/pull/11641), [Gargron](https://github.com/tootsuite/mastodon/pull/11594), [Gargron](https://github.com/tootsuite/mastodon/pull/11517), [mayaeh](https://github.com/tootsuite/mastodon/pull/11845), [Gargron](https://github.com/tootsuite/mastodon/pull/11774), [Gargron](https://github.com/tootsuite/mastodon/pull/11712), [Gargron](https://github.com/tootsuite/mastodon/pull/11791), [Gargron](https://github.com/tootsuite/mastodon/pull/11743), [Gargron](https://github.com/tootsuite/mastodon/pull/11740), [Gargron](https://github.com/tootsuite/mastodon/pull/11714), [ThibG](https://github.com/tootsuite/mastodon/pull/11631), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/11569), [Gargron](https://github.com/tootsuite/mastodon/pull/11524), [Gargron](https://github.com/tootsuite/mastodon/pull/11513))
+  - Add hashtag usage breakdown to admin UI
+  - Add batch actions for hashtags to admin UI
+  - Add trends to web UI
+  - Add trends to public pages
+  - Add user preference to hide trends
+  - Add admin setting to disable trends
+- **Add categories for custom emojis** ([Gargron](https://github.com/tootsuite/mastodon/pull/11196), [Gargron](https://github.com/tootsuite/mastodon/pull/11793), [Gargron](https://github.com/tootsuite/mastodon/pull/11920), [highemerly](https://github.com/tootsuite/mastodon/pull/11876))
+  - Add custom emoji categories to emoji picker in web UI
+  - Add `category` to custom emojis in REST API
+  - Add batch actions for custom emojis in admin UI
+- Add max image dimensions to error message ([raboof](https://github.com/tootsuite/mastodon/pull/11552))
+- Add aac, m4a, 3gp, amr, wma to allowed audio formats ([Gargron](https://github.com/tootsuite/mastodon/pull/11342), [umonaca](https://github.com/tootsuite/mastodon/pull/11687))
+- **Add search syntax for operators and phrases** ([Gargron](https://github.com/tootsuite/mastodon/pull/11411))
+- **Add REST API for managing featured hashtags** ([noellabo](https://github.com/tootsuite/mastodon/pull/11778))
+- **Add REST API for managing timeline read markers** ([Gargron](https://github.com/tootsuite/mastodon/pull/11762))
+- Add `exclude_unreviewed` param to `GET /api/v2/search` REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/11977))
+- **Add ActivityPub secure mode** ([Gargron](https://github.com/tootsuite/mastodon/pull/11269), [ThibG](https://github.com/tootsuite/mastodon/pull/11332), [ThibG](https://github.com/tootsuite/mastodon/pull/11295))
+- Add HTTP signatures to all outgoing ActivityPub GET requests ([Gargron](https://github.com/tootsuite/mastodon/pull/11284), [ThibG](https://github.com/tootsuite/mastodon/pull/11300))
+- Add support for ActivityPub Audio activities ([ThibG](https://github.com/tootsuite/mastodon/pull/11189))
+- Add ActivityPub actor representing the entire server ([ThibG](https://github.com/tootsuite/mastodon/pull/11321), [rtucker](https://github.com/tootsuite/mastodon/pull/11400), [ThibG](https://github.com/tootsuite/mastodon/pull/11561), [Gargron](https://github.com/tootsuite/mastodon/pull/11798))
+- **Add whitelist mode** ([Gargron](https://github.com/tootsuite/mastodon/pull/11291), [mayaeh](https://github.com/tootsuite/mastodon/pull/11634))
+- Add config of multipart threshold for S3 ([ykzts](https://github.com/tootsuite/mastodon/pull/11924), [ykzts](https://github.com/tootsuite/mastodon/pull/11944))
+- Add health check endpoint for web ([ykzts](https://github.com/tootsuite/mastodon/pull/11770), [ykzts](https://github.com/tootsuite/mastodon/pull/11947))
+- Add HTTP signature keyId to request log ([Gargron](https://github.com/tootsuite/mastodon/pull/11591))
+- Add `SMTP_REPLY_TO` environment variable ([hugogameiro](https://github.com/tootsuite/mastodon/pull/11718))
+- Add `tootctl preview_cards remove` command ([mayaeh](https://github.com/tootsuite/mastodon/pull/11320))
+- Add `tootctl media refresh` command ([Gargron](https://github.com/tootsuite/mastodon/pull/11775))
+- Add `tootctl cache recount` command ([Gargron](https://github.com/tootsuite/mastodon/pull/11597))
+- Add option to exclude suspended domains from `tootctl domains crawl` ([dariusk](https://github.com/tootsuite/mastodon/pull/11454))
+- Add soft delete for statuses for instant deletes through API ([Gargron](https://github.com/tootsuite/mastodon/pull/11623), [Gargron](https://github.com/tootsuite/mastodon/pull/11648))
+- Add rails-level JSON caching ([Gargron](https://github.com/tootsuite/mastodon/pull/11333), [Gargron](https://github.com/tootsuite/mastodon/pull/11271))
+- **Add request pool to improve delivery performance** ([Gargron](https://github.com/tootsuite/mastodon/pull/10353), [ykzts](https://github.com/tootsuite/mastodon/pull/11756))
+- Add concurrent connection attempts to resolved IP addresses ([ThibG](https://github.com/tootsuite/mastodon/pull/11757))
+- Add index for remember_token to improve login performance ([abcang](https://github.com/tootsuite/mastodon/pull/11881))
+- **Add more accurate hashtag search** ([Gargron](https://github.com/tootsuite/mastodon/pull/11579), [Gargron](https://github.com/tootsuite/mastodon/pull/11427), [Gargron](https://github.com/tootsuite/mastodon/pull/11448))
+- **Add more accurate account search** ([Gargron](https://github.com/tootsuite/mastodon/pull/11537), [Gargron](https://github.com/tootsuite/mastodon/pull/11580))
+- **Add a spam check** ([Gargron](https://github.com/tootsuite/mastodon/pull/11217), [Gargron](https://github.com/tootsuite/mastodon/pull/11806), [ThibG](https://github.com/tootsuite/mastodon/pull/11296))
+
+### Changed
+
+- **Change conversations UI** ([Gargron](https://github.com/tootsuite/mastodon/pull/11896))
+- Change dashboard to short number notation ([noellabo](https://github.com/tootsuite/mastodon/pull/11847), [noellabo](https://github.com/tootsuite/mastodon/pull/11911))
+- Change REST API `GET /api/v1/timelines/public` to require authentication when public preview is off ([ThibG](https://github.com/tootsuite/mastodon/pull/11802))
+- Change REST API `POST /api/v1/follow_requests/:id/(approve|reject)` to return relationship ([ThibG](https://github.com/tootsuite/mastodon/pull/11800))
+- Change rate limit for media proxy ([ykzts](https://github.com/tootsuite/mastodon/pull/11814))
+- Change unlisted custom emoji to not appear in autosuggestions ([Gargron](https://github.com/tootsuite/mastodon/pull/11818))
+- Change max length of media descriptions from 420 to 1500 characters ([Gargron](https://github.com/tootsuite/mastodon/pull/11819), [ThibG](https://github.com/tootsuite/mastodon/pull/11836))
+- **Change deletes to preserve soft-deleted statuses in unresolved reports** ([Gargron](https://github.com/tootsuite/mastodon/pull/11805))
+- **Change tootctl to use inline parallelization instead of Sidekiq** ([Gargron](https://github.com/tootsuite/mastodon/pull/11776))
+- **Change account deletion page to have better explanations** ([Gargron](https://github.com/tootsuite/mastodon/pull/11753), [Gargron](https://github.com/tootsuite/mastodon/pull/11763))
+- Change hashtag component in web UI to show numbers for 2 last days ([Gargron](https://github.com/tootsuite/mastodon/pull/11742), [Gargron](https://github.com/tootsuite/mastodon/pull/11755), [Gargron](https://github.com/tootsuite/mastodon/pull/11754))
+- Change OpenGraph description on sign-up page to reflect invite ([Gargron](https://github.com/tootsuite/mastodon/pull/11744))
+- Change layout of public profile directory to be the same as in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11705))
+- Change detailed status child ordering to sort self-replies on top ([ThibG](https://github.com/tootsuite/mastodon/pull/11686))
+- Change window resize handler to switch to/from mobile layout as soon as needed ([ThibG](https://github.com/tootsuite/mastodon/pull/11656))
+- Change icon button styles to make hover/focus states more obvious ([ThibG](https://github.com/tootsuite/mastodon/pull/11474))
+- Change contrast of status links that are not mentions or hashtags ([ThibG](https://github.com/tootsuite/mastodon/pull/11406))
+- **Change hashtags to preserve first-used casing** ([Gargron](https://github.com/tootsuite/mastodon/pull/11416), [Gargron](https://github.com/tootsuite/mastodon/pull/11508), [Gargron](https://github.com/tootsuite/mastodon/pull/11504), [Gargron](https://github.com/tootsuite/mastodon/pull/11507), [Gargron](https://github.com/tootsuite/mastodon/pull/11441))
+- **Change unconfirmed user login behaviour** ([Gargron](https://github.com/tootsuite/mastodon/pull/11375), [ThibG](https://github.com/tootsuite/mastodon/pull/11394), [Gargron](https://github.com/tootsuite/mastodon/pull/11860))
+- **Change single-column mode to scroll the whole page** ([Gargron](https://github.com/tootsuite/mastodon/pull/11359), [Gargron](https://github.com/tootsuite/mastodon/pull/11894), [Gargron](https://github.com/tootsuite/mastodon/pull/11891), [ThibG](https://github.com/tootsuite/mastodon/pull/11655), [Gargron](https://github.com/tootsuite/mastodon/pull/11463), [Gargron](https://github.com/tootsuite/mastodon/pull/11458), [ThibG](https://github.com/tootsuite/mastodon/pull/11395), [Gargron](https://github.com/tootsuite/mastodon/pull/11418))
+- Change `tootctl accounts follow` to only work with local accounts ([angristan](https://github.com/tootsuite/mastodon/pull/11592))
+- Change Dockerfile ([Shleeble](https://github.com/tootsuite/mastodon/pull/11710), [ykzts](https://github.com/tootsuite/mastodon/pull/11768), [Shleeble](https://github.com/tootsuite/mastodon/pull/11707))
+- Change supported Node versions to include v12 ([abcang](https://github.com/tootsuite/mastodon/pull/11706))
+- Change Portuguese language from `pt` to `pt-PT` ([Gargron](https://github.com/tootsuite/mastodon/pull/11820))
+- Change domain block silence to always require approval on follow ([ThibG](https://github.com/tootsuite/mastodon/pull/11975))
+
+### Removed
+
+- **Remove OStatus support** ([Gargron](https://github.com/tootsuite/mastodon/pull/11205), [Gargron](https://github.com/tootsuite/mastodon/pull/11303), [Gargron](https://github.com/tootsuite/mastodon/pull/11460), [ThibG](https://github.com/tootsuite/mastodon/pull/11280), [ThibG](https://github.com/tootsuite/mastodon/pull/11278))
+- Remove Atom feeds and old URLs in the form of `GET /:username/updates/:id` ([Gargron](https://github.com/tootsuite/mastodon/pull/11247))
+- Remove WebP support ([angristan](https://github.com/tootsuite/mastodon/pull/11589))
+- Remove deprecated config options from Heroku and Scalingo ([ykzts](https://github.com/tootsuite/mastodon/pull/11925))
+- Remove deprecated REST API `GET /api/v1/search` API ([Gargron](https://github.com/tootsuite/mastodon/pull/11823))
+- Remove deprecated REST API `GET /api/v1/statuses/:id/card` ([Gargron](https://github.com/tootsuite/mastodon/pull/11213))
+- Remove deprecated REST API `POST /api/v1/notifications/dismiss?id=:id` ([Gargron](https://github.com/tootsuite/mastodon/pull/11214))
+- Remove deprecated REST API `GET /api/v1/timelines/direct` ([Gargron](https://github.com/tootsuite/mastodon/pull/11212))
+
+### Fixed
+
+- Fix manifest warning ([ykzts](https://github.com/tootsuite/mastodon/pull/11767))
+- Fix admin UI for custom emoji not respecting GIF autoplay preference ([ThibG](https://github.com/tootsuite/mastodon/pull/11801))
+- Fix page body not being scrollable in admin/settings layout ([Gargron](https://github.com/tootsuite/mastodon/pull/11893))
+- Fix placeholder colors for inputs not being explicitly defined ([Gargron](https://github.com/tootsuite/mastodon/pull/11890))
+- Fix incorrect enclosure length in RSS ([tsia](https://github.com/tootsuite/mastodon/pull/11889))
+- Fix TOTP codes not being filtered from logs during enabling/disabling ([Gargron](https://github.com/tootsuite/mastodon/pull/11877))
+- Fix webfinger response not returning 410 when account is suspended ([Gargron](https://github.com/tootsuite/mastodon/pull/11869))
+- Fix ActivityPub Move handler queuing jobs that will fail if account is suspended ([Gargron](https://github.com/tootsuite/mastodon/pull/11864))
+- Fix SSO login not using existing account when e-mail is verified ([Gargron](https://github.com/tootsuite/mastodon/pull/11862))
+- Fix web UI allowing uploads past status limit via drag & drop ([Gargron](https://github.com/tootsuite/mastodon/pull/11863))
+- Fix expiring polls not being displayed as such in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11835))
+- Fix 2FA challenge and password challenge for non-database users ([Gargron](https://github.com/tootsuite/mastodon/pull/11831), [Gargron](https://github.com/tootsuite/mastodon/pull/11943))
+- Fix profile fields overflowing page width in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11828))
+- Fix web push subscriptions being deleted on rate limit or timeout ([Gargron](https://github.com/tootsuite/mastodon/pull/11826))
+- Fix display of long poll options in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11717), [ThibG](https://github.com/tootsuite/mastodon/pull/11833))
+- Fix search API not resolving URL when `type` is given ([Gargron](https://github.com/tootsuite/mastodon/pull/11822))
+- Fix hashtags being split by ZWNJ character ([Gargron](https://github.com/tootsuite/mastodon/pull/11821))
+- Fix scroll position resetting when opening media modals in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11815))
+- Fix duplicate HTML IDs on about page ([ThibG](https://github.com/tootsuite/mastodon/pull/11803))
+- Fix admin UI showing superfluous reject media/reports on suspended domain blocks ([ThibG](https://github.com/tootsuite/mastodon/pull/11749))
+- Fix ActivityPub context not being dynamically computed ([ThibG](https://github.com/tootsuite/mastodon/pull/11746))
+- Fix Mastodon logo style on hover on public pages' footer ([ThibG](https://github.com/tootsuite/mastodon/pull/11735))
+- Fix height of dashboard counters ([ThibG](https://github.com/tootsuite/mastodon/pull/11736))
+- Fix custom emoji animation on hover in web UI directory bios ([ThibG](https://github.com/tootsuite/mastodon/pull/11716))
+- Fix non-numbers being passed to Redis and causing an error ([Gargron](https://github.com/tootsuite/mastodon/pull/11697))
+- Fix error in REST API for an account's statuses ([Gargron](https://github.com/tootsuite/mastodon/pull/11700))
+- Fix uncaught error when resource param is missing in Webfinger request ([Gargron](https://github.com/tootsuite/mastodon/pull/11701))
+- Fix uncaught domain normalization error in remote follow ([Gargron](https://github.com/tootsuite/mastodon/pull/11703))
+- Fix uncaught 422 and 500 errors ([Gargron](https://github.com/tootsuite/mastodon/pull/11590), [Gargron](https://github.com/tootsuite/mastodon/pull/11811))
+- Fix uncaught parameter missing exceptions and missing error templates ([Gargron](https://github.com/tootsuite/mastodon/pull/11702))
+- Fix encoding error when checking e-mail MX records ([Gargron](https://github.com/tootsuite/mastodon/pull/11696))
+- Fix items in StatusContent render list not all having a key ([ThibG](https://github.com/tootsuite/mastodon/pull/11645))
+- Fix remote and staff-removed statuses leaving media behind for a day ([Gargron](https://github.com/tootsuite/mastodon/pull/11638))
+- Fix CSP needlessly allowing blob URLs in script-src ([ThibG](https://github.com/tootsuite/mastodon/pull/11620))
+- Fix ignoring whole status because of one invalid hashtag ([Gargron](https://github.com/tootsuite/mastodon/pull/11621))
+- Fix hidden statuses losing focus ([ThibG](https://github.com/tootsuite/mastodon/pull/11208))
+- Fix loading bar being obscured by other elements in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11598))
+- Fix multiple issues with replies collection for pages further than self-replies ([ThibG](https://github.com/tootsuite/mastodon/pull/11582))
+- Fix blurhash and autoplay not working on public pages ([Gargron](https://github.com/tootsuite/mastodon/pull/11585))
+- Fix 422 being returned instead of 404 when POSTing to unmatched routes ([Gargron](https://github.com/tootsuite/mastodon/pull/11574), [Gargron](https://github.com/tootsuite/mastodon/pull/11704))
+- Fix client-side resizing of image uploads ([ThibG](https://github.com/tootsuite/mastodon/pull/11570))
+- Fix short number formatting for numbers above million in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11559))
+- Fix ActivityPub and REST API queries setting cookies and preventing caching ([ThibG](https://github.com/tootsuite/mastodon/pull/11539), [ThibG](https://github.com/tootsuite/mastodon/pull/11557), [ThibG](https://github.com/tootsuite/mastodon/pull/11336), [ThibG](https://github.com/tootsuite/mastodon/pull/11331))
+- Fix some emojis in profile metadata labels are not emojified. ([kedamaDQ](https://github.com/tootsuite/mastodon/pull/11534))
+- Fix account search always returning exact match on paginated results ([Gargron](https://github.com/tootsuite/mastodon/pull/11525))
+- Fix acct URIs with IDN domains not being resolved ([Gargron](https://github.com/tootsuite/mastodon/pull/11520))
+- Fix admin dashboard missing latest features ([Gargron](https://github.com/tootsuite/mastodon/pull/11505))
+- Fix jumping of toot date when clicking spoiler button ([ariasuni](https://github.com/tootsuite/mastodon/pull/11449))
+- Fix boost to original audience not working on mobile in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11371))
+- Fix handling of webfinger redirects in ResolveAccountService ([ThibG](https://github.com/tootsuite/mastodon/pull/11279))
+- Fix URLs appearing twice in errors of ActivityPub::DeliveryWorker ([Gargron](https://github.com/tootsuite/mastodon/pull/11231))
+- Fix support for HTTP proxies ([ThibG](https://github.com/tootsuite/mastodon/pull/11245))
+- Fix HTTP requests to IPv6 hosts ([ThibG](https://github.com/tootsuite/mastodon/pull/11240))
+- Fix error in ElasticSearch index import ([mayaeh](https://github.com/tootsuite/mastodon/pull/11192))
+- Fix duplicate account error when seeding development database ([ysksn](https://github.com/tootsuite/mastodon/pull/11366))
+- Fix performance of session clean-up scheduler ([abcang](https://github.com/tootsuite/mastodon/pull/11871))
+- Fix older migrations not running ([zunda](https://github.com/tootsuite/mastodon/pull/11377))
+- Fix URLs counting towards RTL detection ([ahangarha](https://github.com/tootsuite/mastodon/pull/11759))
+- Fix unnecessary status re-rendering in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11211))
+- Fix http_parser.rb gem not being compiled when no network available ([petabyteboy](https://github.com/tootsuite/mastodon/pull/11444))
+- Fix muted text color not applying to all text ([trwnh](https://github.com/tootsuite/mastodon/pull/11996))
+- Fix follower/following lists resetting on back-navigation in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11986))
+
+## [2.9.3] - 2019-08-10
+### Added
+
+- Add GIF and WebP support for custom emojis ([Gargron](https://github.com/tootsuite/mastodon/pull/11519))
+- Add logout link to dropdown menu in web UI ([koyuawsmbrtn](https://github.com/tootsuite/mastodon/pull/11353))
+- Add indication that text search is unavailable in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11112), [ThibG](https://github.com/tootsuite/mastodon/pull/11202))
+- Add `suffix` to `Mastodon::Version` to help forks ([clarfon](https://github.com/tootsuite/mastodon/pull/11407))
+- Add on-hover animation to animated custom emoji in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11348), [ThibG](https://github.com/tootsuite/mastodon/pull/11404), [ThibG](https://github.com/tootsuite/mastodon/pull/11522))
+- Add custom emoji support in profile metadata labels ([ThibG](https://github.com/tootsuite/mastodon/pull/11350))
+
+### Changed
+
+- Change default interface of web and streaming from 0.0.0.0 to 127.0.0.1 ([Gargron](https://github.com/tootsuite/mastodon/pull/11302), [zunda](https://github.com/tootsuite/mastodon/pull/11378), [Gargron](https://github.com/tootsuite/mastodon/pull/11351), [zunda](https://github.com/tootsuite/mastodon/pull/11326))
+- Change the retry limit of web push notifications ([highemerly](https://github.com/tootsuite/mastodon/pull/11292))
+- Change ActivityPub deliveries to not retry HTTP 501 errors ([Gargron](https://github.com/tootsuite/mastodon/pull/11233))
+- Change language detection to include hashtags as words ([Gargron](https://github.com/tootsuite/mastodon/pull/11341))
+- Change terms and privacy policy pages to always be accessible ([Gargron](https://github.com/tootsuite/mastodon/pull/11334))
+- Change robots tag to include `noarchive` when user opts out of indexing ([Kjwon15](https://github.com/tootsuite/mastodon/pull/11421))
+
+### Fixed
+
+- Fix account domain block not clearing out notifications ([Gargron](https://github.com/tootsuite/mastodon/pull/11393))
+- Fix incorrect locale sometimes being detected for browser ([Gargron](https://github.com/tootsuite/mastodon/pull/8657))
+- Fix crash when saving invalid domain name ([Gargron](https://github.com/tootsuite/mastodon/pull/11528))
+- Fix pinned statuses REST API returning pagination headers ([Gargron](https://github.com/tootsuite/mastodon/pull/11526))
+- Fix "cancel follow request" button having unreadable text in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/11521))
+- Fix image uploads being blank when canvas read access is blocked ([ThibG](https://github.com/tootsuite/mastodon/pull/11499))
+- Fix avatars not being animated on hover when not logged in ([ThibG](https://github.com/tootsuite/mastodon/pull/11349))
+- Fix overzealous sanitization of HTML lists ([ThibG](https://github.com/tootsuite/mastodon/pull/11354))
+- Fix block crashing when a follow request exists ([ThibG](https://github.com/tootsuite/mastodon/pull/11288))
+- Fix backup service crashing when an attachment is missing ([ThibG](https://github.com/tootsuite/mastodon/pull/11241))
+- Fix account moderation action always sending e-mail notification ([Gargron](https://github.com/tootsuite/mastodon/pull/11242))
+- Fix swiping columns on mobile sometimes failing in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11200))
+- Fix wrong actor URI being serialized into poll updates ([ThibG](https://github.com/tootsuite/mastodon/pull/11194))
+- Fix statsd UDP sockets not being cleaned up in Sidekiq ([Gargron](https://github.com/tootsuite/mastodon/pull/11230))
+- Fix expiration date of filters being set to "never" when editing them ([ThibG](https://github.com/tootsuite/mastodon/pull/11204))
+- Fix support for MP4 files that are actually M4V files ([Gargron](https://github.com/tootsuite/mastodon/pull/11210))
+- Fix `alerts` not being typecast correctly in push subscription in REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/11343))
+- Fix some notices staying on unrelated pages ([ThibG](https://github.com/tootsuite/mastodon/pull/11364))
+- Fix unboosting sometimes preventing a boost from reappearing on feed ([ThibG](https://github.com/tootsuite/mastodon/pull/11405), [Gargron](https://github.com/tootsuite/mastodon/pull/11450))
+- Fix only one middle dot being recognized in hashtags ([Gargron](https://github.com/tootsuite/mastodon/pull/11345), [ThibG](https://github.com/tootsuite/mastodon/pull/11363))
+- Fix unnecessary SQL query performed on unauthenticated requests ([Gargron](https://github.com/tootsuite/mastodon/pull/11179))
+- Fix incorrect timestamp displayed on featured tags ([Kjwon15](https://github.com/tootsuite/mastodon/pull/11477))
+- Fix privacy dropdown active state when dropdown is placed on top of it ([ThibG](https://github.com/tootsuite/mastodon/pull/11495))
+- Fix filters not being applied to poll options ([ThibG](https://github.com/tootsuite/mastodon/pull/11174))
+- Fix keyboard navigation on various dropdowns ([ThibG](https://github.com/tootsuite/mastodon/pull/11511), [ThibG](https://github.com/tootsuite/mastodon/pull/11492), [ThibG](https://github.com/tootsuite/mastodon/pull/11491))
+- Fix keyboard navigation in modals ([ThibG](https://github.com/tootsuite/mastodon/pull/11493))
+- Fix image conversation being non-deterministic due to timestamps ([Gargron](https://github.com/tootsuite/mastodon/pull/11408))
+- Fix web UI performance ([ThibG](https://github.com/tootsuite/mastodon/pull/11211), [ThibG](https://github.com/tootsuite/mastodon/pull/11234))
+- Fix scrolling to compose form when not necessary in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11246), [ThibG](https://github.com/tootsuite/mastodon/pull/11182))
+- Fix save button being enabled when list title is empty in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11475))
+- Fix poll expiration not being pre-filled on delete & redraft in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11203))
+- Fix content warning sometimes being set when not requested in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/11206))
+
+### Security
+
+- Fix invites not being disabled upon account suspension ([ThibG](https://github.com/tootsuite/mastodon/pull/11412))
+- Fix blocked domains still being able to fill database with account records ([Gargron](https://github.com/tootsuite/mastodon/pull/11219))
+
 ## [2.9.2] - 2019-06-22
 ### Added
 
diff --git a/Gemfile b/Gemfile
index 2505194c8..45a8444fd 100644
--- a/Gemfile
+++ b/Gemfile
@@ -5,7 +5,7 @@ ruby '>= 2.4.0', '< 2.7.0'
 
 gem 'pkg-config', '~> 1.3'
 
-gem 'puma', '~> 4.1'
+gem 'puma', '~> 4.2'
 gem 'rails', '~> 5.2.3'
 gem 'thor', '~> 0.20'
 
@@ -29,7 +29,7 @@ gem 'bootsnap', '~> 1.4', require: false
 gem 'browser'
 gem 'charlock_holmes', '~> 0.7.6'
 gem 'iso-639'
-gem 'chewy', '~> 5.0'
+gem 'chewy', '~> 5.1'
 gem 'cld3', '~> 3.2.4'
 gem 'devise', '~> 4.7'
 gem 'devise-two-factor', '~> 3.1'
@@ -44,13 +44,13 @@ gem 'omniauth-saml', '~> 1.10'
 gem 'omniauth', '~> 1.9'
 
 gem 'discard', '~> 1.1'
-gem 'doorkeeper', '~> 5.1'
+gem 'doorkeeper', '~> 5.2'
 gem 'fast_blank', '~> 1.0'
 gem 'fastimage'
 gem 'goldfinger', '~> 2.1'
 gem 'hiredis', '~> 0.6'
 gem 'redis-namespace', '~> 1.5'
-gem 'health_check', '~> 3.0'
+gem 'health_check', git: 'https://github.com/ianheggie/health_check', ref: '0b799ead604f900ed50685e9b2d469cd2befba5b'
 gem 'html2text'
 gem 'htmlentities', '~> 4.3'
 gem 'http', '~> 3.3'
@@ -118,7 +118,7 @@ end
 group :test do
   gem 'capybara', '~> 3.29'
   gem 'climate_control', '~> 0.2'
-  gem 'faker', '~> 2.3'
+  gem 'faker', '~> 2.4'
   gem 'microformats', '~> 4.1'
   gem 'rails-controller-testing', '~> 1.0'
   gem 'rspec-sidekiq', '~> 3.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 092f69119..c05b85b2a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,4 +1,12 @@
 GIT
+  remote: https://github.com/ianheggie/health_check
+  revision: 0b799ead604f900ed50685e9b2d469cd2befba5b
+  ref: 0b799ead604f900ed50685e9b2d469cd2befba5b
+  specs:
+    health_check (4.0.0.pre)
+      rails (>= 4.0)
+
+GIT
   remote: https://github.com/rtomayko/posix-spawn
   revision: 58465d2e213991f8afb13b984854a49fcdcc980c
   ref: 58465d2e213991f8afb13b984854a49fcdcc980c
@@ -161,7 +169,7 @@ GEM
     case_transform (0.2)
       activesupport
     charlock_holmes (0.7.6)
-    chewy (5.0.0)
+    chewy (5.1.0)
       activesupport (>= 4.0)
       elasticsearch (>= 2.0.0)
       elasticsearch-dsl
@@ -209,19 +217,19 @@ GEM
     docile (1.3.2)
     domain_name (0.5.20180417)
       unf (>= 0.0.5, < 1.0.0)
-    doorkeeper (5.1.0)
+    doorkeeper (5.2.1)
       railties (>= 5)
     dotenv (2.7.5)
     dotenv-rails (2.7.5)
       dotenv (= 2.7.5)
       railties (>= 3.2, < 6.1)
-    elasticsearch (6.0.2)
-      elasticsearch-api (= 6.0.2)
-      elasticsearch-transport (= 6.0.2)
-    elasticsearch-api (6.0.2)
+    elasticsearch (7.3.0)
+      elasticsearch-api (= 7.3.0)
+      elasticsearch-transport (= 7.3.0)
+    elasticsearch-api (7.3.0)
       multi_json
-    elasticsearch-dsl (0.1.5)
-    elasticsearch-transport (6.0.2)
+    elasticsearch-dsl (0.1.8)
+    elasticsearch-transport (7.3.0)
       faraday
       multi_json
     encryptor (3.0.0)
@@ -231,9 +239,9 @@ GEM
       tzinfo
     excon (0.62.0)
     fabrication (2.20.2)
-    faker (2.3.0)
+    faker (2.4.0)
       i18n (~> 1.6.0)
-    faraday (0.15.0)
+    faraday (0.15.4)
       multipart-post (>= 1.2, < 3)
     fast_blank (1.0.0)
     fastimage (2.1.7)
@@ -278,8 +286,6 @@ GEM
       concurrent-ruby (~> 1.0)
     hashdiff (1.0.0)
     hashie (3.6.0)
-    health_check (3.0.0)
-      railties (>= 5.0)
     heapy (0.1.4)
     highline (2.0.1)
     hiredis (0.6.3)
@@ -372,10 +378,10 @@ GEM
     mimemagic (0.3.3)
     mini_mime (1.0.2)
     mini_portile2 (2.4.0)
-    minitest (5.11.3)
+    minitest (5.12.0)
     msgpack (1.3.1)
     multi_json (1.13.1)
-    multipart-post (2.0.0)
+    multipart-post (2.1.1)
     necromancer (0.5.0)
     net-ldap (0.16.1)
     net-scp (2.0.0)
@@ -447,7 +453,7 @@ GEM
     pry-rails (0.3.9)
       pry (>= 0.10.4)
     public_suffix (4.0.1)
-    puma (4.1.1)
+    puma (4.2.0)
       nio4r (~> 2.0)
     pundit (2.1.0)
       activesupport (>= 3.0.0)
@@ -503,7 +509,7 @@ GEM
     rdf-normalize (0.3.3)
       rdf (>= 2.2, < 4.0)
     redcarpet (3.4.0)
-    redis (4.1.2)
+    redis (4.1.3)
     redis-actionpack (5.0.2)
       actionpack (>= 4.0, < 6)
       redis-rack (>= 1, < 3)
@@ -593,7 +599,7 @@ GEM
     simple_form (4.1.0)
       actionpack (>= 5.0)
       activemodel (>= 5.0)
-    simplecov (0.17.0)
+    simplecov (0.17.1)
       docile (~> 1.1)
       json (>= 1.8, < 3)
       simplecov-html (~> 0.10.0)
@@ -649,7 +655,7 @@ GEM
     uniform_notifier (1.12.1)
     warden (1.2.8)
       rack (>= 2.0.6)
-    webmock (3.7.3)
+    webmock (3.7.5)
       addressable (>= 2.3.6)
       crack (>= 0.3.2)
       hashdiff (>= 0.4.0, < 2.0.0)
@@ -690,7 +696,7 @@ DEPENDENCIES
   capistrano-yarn (~> 2.0)
   capybara (~> 3.29)
   charlock_holmes (~> 0.7.6)
-  chewy (~> 5.0)
+  chewy (~> 5.1)
   cld3 (~> 3.2.4)
   climate_control (~> 0.2)
   concurrent-ruby
@@ -700,10 +706,10 @@ DEPENDENCIES
   devise-two-factor (~> 3.1)
   devise_pam_authenticatable2 (~> 9.2)
   discard (~> 1.1)
-  doorkeeper (~> 5.1)
+  doorkeeper (~> 5.2)
   dotenv-rails (~> 2.7)
   fabrication (~> 2.20)
-  faker (~> 2.3)
+  faker (~> 2.4)
   fast_blank (~> 1.0)
   fastimage
   fog-core (<= 2.1.0)
@@ -711,7 +717,7 @@ DEPENDENCIES
   fuubar (~> 2.4)
   goldfinger (~> 2.1)
   hamlit-rails (~> 0.2)
-  health_check (~> 3.0)
+  health_check!
   hiredis (~> 0.6)
   html2text
   htmlentities (~> 4.3)
@@ -756,7 +762,7 @@ DEPENDENCIES
   private_address_check (~> 0.5)
   pry-byebug (~> 3.7)
   pry-rails (~> 0.3)
-  puma (~> 4.1)
+  puma (~> 4.2)
   pundit (~> 2.1)
   rack-attack (~> 6.1)
   rack-cors (~> 1.0)
@@ -798,7 +804,7 @@ DEPENDENCIES
   webpush
 
 RUBY VERSION
-   ruby 2.6.1p33
+   ruby 2.6.4p104
 
 BUNDLED WITH
    1.17.3
diff --git a/app.json b/app.json
index 09adaac2c..211f17d81 100644
--- a/app.json
+++ b/app.json
@@ -13,15 +13,6 @@
       "description": "The domain that your Mastodon instance will run on (this can be appname.herokuapp.com or a custom domain)",
       "required": true
     },
-    "LOCAL_HTTPS": {
-      "description": "Will your domain support HTTPS? (Automatic for herokuapp, requires manual configuration for custom domains)",
-      "value": "false",
-      "required": true
-    },
-    "PAPERCLIP_SECRET": {
-      "description": "The secret key for storing media files",
-      "generator": "secret"
-    },
     "SECRET_KEY_BASE": {
       "description": "The secret key base",
       "generator": "secret"
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb
index 7b0438127..5d5db937c 100644
--- a/app/controllers/about_controller.rb
+++ b/app/controllers/about_controller.rb
@@ -4,9 +4,7 @@ class AboutController < ApplicationController
   before_action :set_pack
   layout 'public'
 
-  before_action :require_open_federation!, only: [:show, :more, :blocks]
-  before_action :check_blocklist_enabled, only: [:blocks]
-  before_action :authenticate_user!, only: [:blocks], if: :blocklist_account_required?
+  before_action :require_open_federation!, only: [:show, :more]
   before_action :set_body_classes, only: :show
   before_action :set_instance_presenter
   before_action :set_expires_in, only: [:show, :more, :terms]
@@ -17,15 +15,20 @@ class AboutController < ApplicationController
 
   def more
     flash.now[:notice] = I18n.t('about.instance_actor_flash') if params[:instance_actor]
+
+    toc_generator = TOCGenerator.new(@instance_presenter.site_extended_description)
+
+    @contents          = toc_generator.html
+    @table_of_contents = toc_generator.toc
+    @blocks            = DomainBlock.with_user_facing_limitations.by_severity if display_blocks?
   end
 
   def terms; end
 
-  def blocks
-    @show_rationale = Setting.show_domain_blocks_rationale == 'all'
-    @show_rationale |= Setting.show_domain_blocks_rationale == 'users' && !current_user.nil? && current_user.functional?
-    @blocks = DomainBlock.with_user_facing_limitations.order('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), reject_media, domain').to_a
-  end
+  helper_method :display_blocks?
+  helper_method :display_blocks_rationale?
+  helper_method :public_fetch_mode?
+  helper_method :new_user
 
   private
 
@@ -33,28 +36,14 @@ class AboutController < ApplicationController
     not_found if whitelist_mode?
   end
 
-  def check_blocklist_enabled
-    not_found if Setting.show_domain_blocks == 'disabled'
-  end
-
-  def blocklist_account_required?
-    Setting.show_domain_blocks == 'users'
+  def display_blocks?
+    Setting.show_domain_blocks == 'all' || (Setting.show_domain_blocks == 'users' && user_signed_in?)
   end
 
-  def block_severity_text(block)
-    if block.severity == 'suspend'
-      I18n.t('domain_blocks.suspension')
-    else
-      limitations = []
-      limitations << I18n.t('domain_blocks.media_block') if block.reject_media?
-      limitations << I18n.t('domain_blocks.silence') if block.severity == 'silence'
-      limitations.join(', ')
-    end
+  def display_blocks_rationale?
+    Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?)
   end
 
-  helper_method :block_severity_text
-  helper_method :public_fetch_mode?
-
   def new_user
     User.new.tap do |user|
       user.build_account
@@ -62,8 +51,6 @@ class AboutController < ApplicationController
     end
   end
 
-  helper_method :new_user
-
   def set_pack
     use_pack 'public'
   end
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 817e5e832..1c36813d0 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -10,6 +10,7 @@ class AccountsController < ApplicationController
   before_action :set_body_classes
 
   skip_around_action :set_locale, if: -> { request.format == :json }
+  skip_before_action :require_functional!
 
   def show
     respond_to do |format|
diff --git a/app/controllers/activitypub/collections_controller.rb b/app/controllers/activitypub/collections_controller.rb
index 989fee385..910fefb1c 100644
--- a/app/controllers/activitypub/collections_controller.rb
+++ b/app/controllers/activitypub/collections_controller.rb
@@ -33,9 +33,9 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
   def scope_for_collection
     case params[:id]
     when 'featured'
-      @account.statuses.permitted_for(@account, signed_request_account).tap do |scope|
-        scope.merge!(@account.pinned_statuses)
-      end
+      return Status.none if @account.blocking?(signed_request_account)
+
+      @account.pinned_statuses
     else
       raise ActiveRecord::RecordNotFound
     end
diff --git a/app/controllers/admin/relays_controller.rb b/app/controllers/admin/relays_controller.rb
index 1b02d3c36..6fbb6e063 100644
--- a/app/controllers/admin/relays_controller.rb
+++ b/app/controllers/admin/relays_controller.rb
@@ -3,6 +3,7 @@
 module Admin
   class RelaysController < BaseController
     before_action :set_relay, except: [:index, :new, :create]
+    before_action :require_signatures_enabled!, only: [:new, :create, :enable]
 
     def index
       authorize :relay, :update?
@@ -11,7 +12,7 @@ module Admin
 
     def new
       authorize :relay, :update?
-      @relay = Relay.new(inbox_url: Relay::PRESET_RELAY)
+      @relay = Relay.new
     end
 
     def create
@@ -54,5 +55,9 @@ module Admin
     def resource_params
       params.require(:relay).permit(:inbox_url)
     end
+
+    def require_signatures_enabled!
+      redirect_to admin_relays_path, alert: I18n.t('admin.relays.signatures_not_enabled') if authorized_fetch_mode?
+    end
   end
 end
diff --git a/app/controllers/admin/two_factor_authentications_controller.rb b/app/controllers/admin/two_factor_authentications_controller.rb
index 2577a4b17..0652c3a7a 100644
--- a/app/controllers/admin/two_factor_authentications_controller.rb
+++ b/app/controllers/admin/two_factor_authentications_controller.rb
@@ -8,6 +8,7 @@ module Admin
       authorize @user, :disable_2fa?
       @user.disable_two_factor!
       log_action :disable_2fa, @user
+      UserMailer.two_factor_disabled(@user).deliver_later!
       redirect_to admin_accounts_path
     end
 
diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb
index 0787cd636..333db9618 100644
--- a/app/controllers/api/v1/accounts/statuses_controller.rb
+++ b/app/controllers/api/v1/accounts/statuses_controller.rb
@@ -57,6 +57,8 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
   end
 
   def pinned_scope
+    return Status.none if @account.blocking?(current_account)
+
     @account.pinned_statuses
   end
 
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index b306e8e8c..c12e1c12e 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -33,7 +33,7 @@ class Api::V1::AccountsController < Api::BaseController
   def follow
     FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs))
 
-    options = @account.locked? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } }
+    options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } }
 
     render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options)
   end
diff --git a/app/controllers/api/v2/search_controller.rb b/app/controllers/api/v2/search_controller.rb
index 7fdc030e5..76decdb25 100644
--- a/app/controllers/api/v2/search_controller.rb
+++ b/app/controllers/api/v2/search_controller.rb
@@ -22,7 +22,7 @@ class Api::V2::SearchController < Api::BaseController
       params[:q],
       current_account,
       limit_param(RESULTS_LIMIT),
-      search_params.merge(resolve: truthy_param?(:resolve))
+      search_params.merge(resolve: truthy_param?(:resolve), exclude_unreviewed: truthy_param?(:exclude_unreviewed))
     )
   end
 
diff --git a/app/controllers/auth/challenges_controller.rb b/app/controllers/auth/challenges_controller.rb
new file mode 100644
index 000000000..41827b21c
--- /dev/null
+++ b/app/controllers/auth/challenges_controller.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class Auth::ChallengesController < ApplicationController
+  include ChallengableConcern
+
+  layout 'auth'
+
+  before_action :set_pack
+  before_action :authenticate_user!
+
+  skip_before_action :require_functional!
+
+  def create
+    if challenge_passed?
+      session[:challenge_passed_at] = Time.now.utc
+      redirect_to challenge_params[:return_to]
+    else
+      @challenge = Form::Challenge.new(return_to: challenge_params[:return_to])
+      flash.now[:alert] = I18n.t('challenge.invalid_password')
+      render_challenge
+    end
+  end
+
+  private
+
+  def set_pack
+    use_pack 'auth'
+  end
+end
diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb
index c2b38883b..efde02ac2 100644
--- a/app/controllers/auth/sessions_controller.rb
+++ b/app/controllers/auth/sessions_controller.rb
@@ -9,6 +9,7 @@ class Auth::SessionsController < Devise::SessionsController
   skip_before_action :require_functional!
 
   prepend_before_action :set_pack
+  prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]
 
   before_action :set_instance_presenter, only: [:new]
   before_action :set_body_classes
@@ -22,34 +23,32 @@ class Auth::SessionsController < Devise::SessionsController
   end
 
   def create
-    self.resource = begin
-      if user_params[:email].blank? && session[:otp_user_id].present?
-        User.find(session[:otp_user_id])
-      else
-        warden.authenticate!(auth_options)
-      end
-    end
-
-    if resource.otp_required_for_login?
-      if user_params[:otp_attempt].present? && session[:otp_user_id].present?
-        authenticate_with_two_factor_via_otp(resource)
-      else
-        prompt_for_two_factor(resource)
-      end
-    else
-      authenticate_and_respond(resource)
+    super do |resource|
+      remember_me(resource)
+      flash.delete(:notice)
     end
   end
 
   def destroy
     tmp_stored_location = stored_location_for(:user)
     super
+    session.delete(:challenge_passed_at)
     flash.delete(:notice)
     store_location_for(:user, tmp_stored_location) if continue_after?
   end
 
   protected
 
+  def find_user
+    if session[:otp_user_id]
+      User.find(session[:otp_user_id])
+    else
+      user   = User.authenticate_with_ldap(user_params) if Devise.ldap_authentication
+      user ||= User.authenticate_with_pam(user_params) if Devise.pam_authentication
+      user ||= User.find_for_authentication(email: user_params[:email])
+    end
+  end
+
   def user_params
     params.require(:user).permit(:email, :password, :otp_attempt)
   end
@@ -72,6 +71,10 @@ class Auth::SessionsController < Devise::SessionsController
     super
   end
 
+  def two_factor_enabled?
+    find_user&.otp_required_for_login?
+  end
+
   def valid_otp_attempt?(user)
     user.validate_and_consume_otp!(user_params[:otp_attempt]) ||
       user.invalidate_otp_backup_code!(user_params[:otp_attempt])
@@ -79,10 +82,24 @@ class Auth::SessionsController < Devise::SessionsController
     false
   end
 
+  def authenticate_with_two_factor
+    user = self.resource = find_user
+
+    if user_params[:otp_attempt].present? && session[:otp_user_id]
+      authenticate_with_two_factor_via_otp(user)
+    elsif user.present? && (user.encrypted_password.blank? || user.valid_password?(user_params[:password]))
+      # If encrypted_password is blank, we got the user from LDAP or PAM,
+      # so credentials are already valid
+
+      prompt_for_two_factor(user)
+    end
+  end
+
   def authenticate_with_two_factor_via_otp(user)
     if valid_otp_attempt?(user)
       session.delete(:otp_user_id)
-      authenticate_and_respond(user)
+      remember_me(user)
+      sign_in(user)
     else
       flash.now[:alert] = I18n.t('users.invalid_otp_token')
       prompt_for_two_factor(user)
@@ -91,16 +108,10 @@ class Auth::SessionsController < Devise::SessionsController
 
   def prompt_for_two_factor(user)
     session[:otp_user_id] = user.id
+    @body_classes = 'lighter'
     render :two_factor
   end
 
-  def authenticate_and_respond(user)
-    sign_in(user)
-    remember_me(user)
-
-    respond_with user, location: after_sign_in_path_for(user)
-  end
-
   private
 
   def set_pack
@@ -117,11 +128,9 @@ class Auth::SessionsController < Devise::SessionsController
 
   def home_paths(resource)
     paths = [about_path]
-
     if single_user_mode? && resource.is_a?(User)
       paths << short_account_path(username: resource.account)
     end
-
     paths
   end
 
diff --git a/app/controllers/concerns/challengable_concern.rb b/app/controllers/concerns/challengable_concern.rb
new file mode 100644
index 000000000..b29d90b3c
--- /dev/null
+++ b/app/controllers/concerns/challengable_concern.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+# This concern is inspired by "sudo mode" on GitHub. It
+# is a way to re-authenticate a user before allowing them
+# to see or perform an action.
+#
+# Add `before_action :require_challenge!` to actions you
+# want to protect.
+#
+# The user will be shown a page to enter the challenge (which
+# is either the password, or just the username when no
+# password exists). Upon passing, there is a grace period
+# during which no challenge will be asked from the user.
+#
+# Accessing challenge-protected resources during the grace
+# period will refresh the grace period.
+module ChallengableConcern
+  extend ActiveSupport::Concern
+
+  CHALLENGE_TIMEOUT = 1.hour.freeze
+
+  def require_challenge!
+    return if skip_challenge?
+
+    if challenge_passed_recently?
+      session[:challenge_passed_at] = Time.now.utc
+      return
+    end
+
+    @challenge = Form::Challenge.new(return_to: request.url)
+
+    if params.key?(:form_challenge)
+      if challenge_passed?
+        session[:challenge_passed_at] = Time.now.utc
+        return
+      else
+        flash.now[:alert] = I18n.t('challenge.invalid_password')
+        render_challenge
+      end
+    else
+      render_challenge
+    end
+  end
+
+  def render_challenge
+    @body_classes = 'lighter'
+    render template: 'auth/challenges/new', layout: 'auth'
+  end
+
+  def challenge_passed?
+    current_user.valid_password?(challenge_params[:current_password])
+  end
+
+  def skip_challenge?
+    current_user.encrypted_password.blank?
+  end
+
+  def challenge_passed_recently?
+    session[:challenge_passed_at].present? && session[:challenge_passed_at] >= CHALLENGE_TIMEOUT.ago
+  end
+
+  def challenge_params
+    params.require(:form_challenge).permit(:current_password, :return_to)
+  end
+end
diff --git a/app/controllers/concerns/export_controller_concern.rb b/app/controllers/concerns/export_controller_concern.rb
index e20b71a30..bfe990c82 100644
--- a/app/controllers/concerns/export_controller_concern.rb
+++ b/app/controllers/concerns/export_controller_concern.rb
@@ -5,7 +5,10 @@ module ExportControllerConcern
 
   included do
     before_action :authenticate_user!
+    before_action :require_not_suspended!
     before_action :load_export
+
+    skip_before_action :require_functional!
   end
 
   private
@@ -27,4 +30,8 @@ module ExportControllerConcern
   def export_filename
     "#{controller_name}.csv"
   end
+
+  def require_not_suspended!
+    forbidden if current_account.suspended?
+  end
 end
diff --git a/app/controllers/custom_css_controller.rb b/app/controllers/custom_css_controller.rb
index e3f67bd14..0a667a6a6 100644
--- a/app/controllers/custom_css_controller.rb
+++ b/app/controllers/custom_css_controller.rb
@@ -2,6 +2,7 @@
 
 class CustomCssController < ApplicationController
   skip_before_action :store_current_location
+  skip_before_action :require_functional!
 
   before_action :set_cache_headers
 
diff --git a/app/controllers/directories_controller.rb b/app/controllers/directories_controller.rb
index bbfdde8af..adf2bd014 100644
--- a/app/controllers/directories_controller.rb
+++ b/app/controllers/directories_controller.rb
@@ -10,6 +10,8 @@ class DirectoriesController < ApplicationController
   before_action :set_accounts
   before_action :set_pack
 
+  skip_before_action :require_functional!
+
   def index
     render :index
   end
diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb
index 4641a8bb9..df46f5f72 100644
--- a/app/controllers/follower_accounts_controller.rb
+++ b/app/controllers/follower_accounts_controller.rb
@@ -8,6 +8,7 @@ class FollowerAccountsController < ApplicationController
   before_action :set_cache_headers
 
   skip_around_action :set_locale, if: -> { request.format == :json }
+  skip_before_action :require_functional!
 
   def index
     respond_to do |format|
diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb
index 6e80554fb..8cab67ff5 100644
--- a/app/controllers/following_accounts_controller.rb
+++ b/app/controllers/following_accounts_controller.rb
@@ -8,6 +8,7 @@ class FollowingAccountsController < ApplicationController
   before_action :set_cache_headers
 
   skip_around_action :set_locale, if: -> { request.format == :json }
+  skip_before_action :require_functional!
 
   def index
     respond_to do |format|
diff --git a/app/controllers/manifests_controller.rb b/app/controllers/manifests_controller.rb
index 491cde745..960510f60 100644
--- a/app/controllers/manifests_controller.rb
+++ b/app/controllers/manifests_controller.rb
@@ -2,6 +2,7 @@
 
 class ManifestsController < ApplicationController
   skip_before_action :store_current_location
+  skip_before_action :require_functional!
 
   def show
     expires_in 3.minutes, public: true
diff --git a/app/controllers/media_controller.rb b/app/controllers/media_controller.rb
index 1f693de32..05cf09c28 100644
--- a/app/controllers/media_controller.rb
+++ b/app/controllers/media_controller.rb
@@ -4,6 +4,7 @@ class MediaController < ApplicationController
   include Authorization
 
   skip_before_action :store_current_location
+  skip_before_action :require_functional!
 
   before_action :authenticate_user!, if: :whitelist_mode?
   before_action :set_media_attachment
diff --git a/app/controllers/media_proxy_controller.rb b/app/controllers/media_proxy_controller.rb
index 47544f21c..014b89de1 100644
--- a/app/controllers/media_proxy_controller.rb
+++ b/app/controllers/media_proxy_controller.rb
@@ -4,6 +4,7 @@ class MediaProxyController < ApplicationController
   include RoutingHelper
 
   skip_before_action :store_current_location
+  skip_before_action :require_functional!
 
   before_action :authenticate_user!, if: :whitelist_mode?
 
diff --git a/app/controllers/remote_follow_controller.rb b/app/controllers/remote_follow_controller.rb
index 65dfa35db..93a0a7476 100644
--- a/app/controllers/remote_follow_controller.rb
+++ b/app/controllers/remote_follow_controller.rb
@@ -8,6 +8,8 @@ class RemoteFollowController < ApplicationController
   before_action :set_pack
   before_action :set_body_classes
 
+  skip_before_action :require_functional!
+
   def new
     @remote_follow = RemoteFollow.new(session_params)
   end
diff --git a/app/controllers/remote_interaction_controller.rb b/app/controllers/remote_interaction_controller.rb
index 6b797b10f..e058d0ed5 100644
--- a/app/controllers/remote_interaction_controller.rb
+++ b/app/controllers/remote_interaction_controller.rb
@@ -11,6 +11,8 @@ class RemoteInteractionController < ApplicationController
   before_action :set_body_classes
   before_action :set_pack
 
+  skip_before_action :require_functional!
+
   def new
     @remote_follow = RemoteFollow.new(session_params)
   end
diff --git a/app/controllers/settings/aliases_controller.rb b/app/controllers/settings/aliases_controller.rb
new file mode 100644
index 000000000..b7c9a409d
--- /dev/null
+++ b/app/controllers/settings/aliases_controller.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+class Settings::AliasesController < Settings::BaseController
+  layout 'admin'
+
+  before_action :authenticate_user!
+  before_action :set_aliases, except: :destroy
+  before_action :set_alias, only: :destroy
+
+  def index
+    @alias = current_account.aliases.build
+  end
+
+  def create
+    @alias = current_account.aliases.build(resource_params)
+
+    if @alias.save
+      ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
+      redirect_to settings_aliases_path, notice: I18n.t('aliases.created_msg')
+    else
+      render :index
+    end
+  end
+
+  def destroy
+    @alias.destroy!
+    redirect_to settings_aliases_path, notice: I18n.t('aliases.deleted_msg')
+  end
+
+  private
+
+  def resource_params
+    params.require(:account_alias).permit(:acct)
+  end
+
+  def set_alias
+    @alias = current_account.aliases.find(params[:id])
+  end
+
+  def set_aliases
+    @aliases = current_account.aliases.order(id: :desc).reject(&:new_record?)
+  end
+end
diff --git a/app/controllers/settings/exports_controller.rb b/app/controllers/settings/exports_controller.rb
index 3012fbf77..0e93d07a9 100644
--- a/app/controllers/settings/exports_controller.rb
+++ b/app/controllers/settings/exports_controller.rb
@@ -6,6 +6,9 @@ class Settings::ExportsController < Settings::BaseController
   layout 'admin'
 
   before_action :authenticate_user!
+  before_action :require_not_suspended!
+
+  skip_before_action :require_functional!
 
   def show
     @export  = Export.new(current_account)
@@ -34,4 +37,8 @@ class Settings::ExportsController < Settings::BaseController
   def lock_options
     { redis: Redis.current, key: "backup:#{current_user.id}" }
   end
+
+  def require_not_suspended!
+    forbidden if current_account.suspended?
+  end
 end
diff --git a/app/controllers/settings/migration/redirects_controller.rb b/app/controllers/settings/migration/redirects_controller.rb
new file mode 100644
index 000000000..6e5b72ffb
--- /dev/null
+++ b/app/controllers/settings/migration/redirects_controller.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+class Settings::Migration::RedirectsController < Settings::BaseController
+  layout 'admin'
+
+  before_action :authenticate_user!
+  before_action :require_not_suspended!
+
+  skip_before_action :require_functional!
+
+  def new
+    @redirect = Form::Redirect.new
+  end
+
+  def create
+    @redirect = Form::Redirect.new(resource_params.merge(account: current_account))
+
+    if @redirect.valid_with_challenge?(current_user)
+      current_account.update!(moved_to_account: @redirect.target_account)
+      ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
+      redirect_to settings_migration_path, notice: I18n.t('migrations.moved_msg', acct: current_account.moved_to_account.acct)
+    else
+      render :new
+    end
+  end
+
+  def destroy
+    if current_account.moved_to_account_id.present?
+      current_account.update!(moved_to_account: nil)
+      ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
+    end
+
+    redirect_to settings_migration_path, notice: I18n.t('migrations.cancelled_msg')
+  end
+
+  private
+
+  def resource_params
+    params.require(:form_redirect).permit(:acct, :current_password, :current_username)
+  end
+
+  def require_not_suspended!
+    forbidden if current_account.suspended?
+  end
+end
diff --git a/app/controllers/settings/migrations_controller.rb b/app/controllers/settings/migrations_controller.rb
index 59eb48779..68304bb51 100644
--- a/app/controllers/settings/migrations_controller.rb
+++ b/app/controllers/settings/migrations_controller.rb
@@ -4,31 +4,48 @@ class Settings::MigrationsController < Settings::BaseController
   layout 'admin'
 
   before_action :authenticate_user!
+  before_action :require_not_suspended!
+  before_action :set_migrations
+  before_action :set_cooldown
+
+  skip_before_action :require_functional!
 
   def show
-    @migration = Form::Migration.new(account: current_account.moved_to_account)
+    @migration = current_account.migrations.build
   end
 
-  def update
-    @migration = Form::Migration.new(resource_params)
+  def create
+    @migration = current_account.migrations.build(resource_params)
 
-    if @migration.valid? && migration_account_changed?
-      current_account.update!(moved_to_account: @migration.account)
-      ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
-      redirect_to settings_migration_path, notice: I18n.t('migrations.updated_msg')
+    if @migration.save_with_challenge(current_user)
+      MoveService.new.call(@migration)
+      redirect_to settings_migration_path, notice: I18n.t('migrations.moved_msg', acct: current_account.moved_to_account.acct)
     else
       render :show
     end
   end
 
+  helper_method :on_cooldown?
+
   private
 
   def resource_params
-    params.require(:migration).permit(:acct)
+    params.require(:account_migration).permit(:acct, :current_password, :current_username)
+  end
+
+  def set_migrations
+    @migrations = current_account.migrations.includes(:target_account).order(id: :desc).reject(&:new_record?)
+  end
+
+  def set_cooldown
+    @cooldown = current_account.migrations.within_cooldown.first
+  end
+
+  def on_cooldown?
+    @cooldown.present?
   end
 
-  def migration_account_changed?
-    current_account.moved_to_account_id != @migration.account&.id &&
-      current_account.id != @migration.account&.id
+  def require_not_suspended!
+    forbidden if current_account.suspended?
   end
 end
diff --git a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
index 46c90bf74..ef4df3339 100644
--- a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
+++ b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
@@ -3,9 +3,12 @@
 module Settings
   module TwoFactorAuthentication
     class ConfirmationsController < BaseController
+      include ChallengableConcern
+
       layout 'admin'
 
       before_action :authenticate_user!
+      before_action :require_challenge!
       before_action :ensure_otp_secret
 
       skip_before_action :require_functional!
@@ -22,6 +25,8 @@ module Settings
           @recovery_codes = current_user.generate_otp_backup_codes!
           current_user.save!
 
+          UserMailer.two_factor_enabled(current_user).deliver_later!
+
           render 'settings/two_factor_authentication/recovery_codes/index'
         else
           flash.now[:alert] = I18n.t('two_factor_authentication.wrong_code')
diff --git a/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
index 09a759860..0c4f5bff7 100644
--- a/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
+++ b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
@@ -3,16 +3,22 @@
 module Settings
   module TwoFactorAuthentication
     class RecoveryCodesController < BaseController
+      include ChallengableConcern
+
       layout 'admin'
 
       before_action :authenticate_user!
+      before_action :require_challenge!, on: :create
 
       skip_before_action :require_functional!
 
       def create
         @recovery_codes = current_user.generate_otp_backup_codes!
         current_user.save!
+
+        UserMailer.two_factor_recovery_codes_changed(current_user).deliver_later!
         flash.now[:notice] = I18n.t('two_factor_authentication.recovery_codes_regenerated')
+
         render :index
       end
     end
diff --git a/app/controllers/settings/two_factor_authentications_controller.rb b/app/controllers/settings/two_factor_authentications_controller.rb
index c93b17577..9118a7933 100644
--- a/app/controllers/settings/two_factor_authentications_controller.rb
+++ b/app/controllers/settings/two_factor_authentications_controller.rb
@@ -2,10 +2,13 @@
 
 module Settings
   class TwoFactorAuthenticationsController < BaseController
+    include ChallengableConcern
+
     layout 'admin'
 
     before_action :authenticate_user!
     before_action :verify_otp_required, only: [:create]
+    before_action :require_challenge!, only: [:create]
 
     skip_before_action :require_functional!
 
@@ -23,6 +26,7 @@ module Settings
       if acceptable_code?
         current_user.otp_required_for_login = false
         current_user.save!
+        UserMailer.two_factor_disabled(current_user).deliver_later!
         redirect_to settings_two_factor_authentication_path
       else
         flash.now[:alert] = I18n.t('two_factor_authentication.wrong_code')
diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb
index 83c412d5c..1b00d38c9 100644
--- a/app/controllers/statuses_controller.rb
+++ b/app/controllers/statuses_controller.rb
@@ -19,6 +19,7 @@ class StatusesController < ApplicationController
   before_action :set_autoplay, only: :embed
 
   skip_around_action :set_locale, if: -> { request.format == :json }
+  skip_before_action :require_functional!, only: [:show, :embed]
 
   content_security_policy only: :embed do |p|
     p.frame_ancestors(false)
diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb
index c447a3a2b..ef61c980f 100644
--- a/app/controllers/tags_controller.rb
+++ b/app/controllers/tags_controller.rb
@@ -13,6 +13,8 @@ class TagsController < ApplicationController
   before_action :set_body_classes
   before_action :set_instance_presenter
 
+  skip_before_action :require_functional!
+
   def show
     respond_to do |format|
       format.html do
diff --git a/app/controllers/well_known/nodeinfo_controller.rb b/app/controllers/well_known/nodeinfo_controller.rb
new file mode 100644
index 000000000..11a699ebc
--- /dev/null
+++ b/app/controllers/well_known/nodeinfo_controller.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module WellKnown
+  class NodeInfoController < ActionController::Base
+    include CacheConcern
+
+    before_action { response.headers['Vary'] = 'Accept' }
+
+    def index
+      expires_in 3.days, public: true
+      render_with_cache json: {}, serializer: NodeInfo::DiscoverySerializer, adapter: NodeInfo::Adapter, expires_in: 3.days, root: 'nodeinfo'
+    end
+
+    def show
+      expires_in 30.minutes, public: true
+      render_with_cache json: {}, serializer: NodeInfo::Serializer, adapter: NodeInfo::Adapter, expires_in: 30.minutes, root: 'nodeinfo'
+    end
+  end
+end
diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb
index 2b3fd1263..ecc73baf5 100644
--- a/app/helpers/settings_helper.rb
+++ b/app/helpers/settings_helper.rb
@@ -87,4 +87,12 @@ module SettingsHelper
       'desktop'
     end
   end
+
+  def compact_account_link_to(account)
+    return if account.nil?
+
+    link_to ActivityPub::TagManager.instance.url_for(account), class: 'name-tag', title: account.acct do
+      safe_join([image_tag(account.avatar.url, width: 15, height: 15, alt: display_name(account), class: 'avatar'), content_tag(:span, account.acct, class: 'username')], ' ')
+    end
+  end
 end
diff --git a/app/javascript/flavours/glitch/actions/blocks.js b/app/javascript/flavours/glitch/actions/blocks.js
index 498ce519f..adae9d83c 100644
--- a/app/javascript/flavours/glitch/actions/blocks.js
+++ b/app/javascript/flavours/glitch/actions/blocks.js
@@ -1,6 +1,7 @@
 import api, { getLinks } from 'flavours/glitch/util/api';
 import { fetchRelationships } from './accounts';
 import { importFetchedAccounts } from './importer';
+import { openModal } from './modal';
 
 export const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST';
 export const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS';
@@ -10,6 +11,8 @@ export const BLOCKS_EXPAND_REQUEST = 'BLOCKS_EXPAND_REQUEST';
 export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS';
 export const BLOCKS_EXPAND_FAIL    = 'BLOCKS_EXPAND_FAIL';
 
+export const BLOCKS_INIT_MODAL = 'BLOCKS_INIT_MODAL';
+
 export function fetchBlocks() {
   return (dispatch, getState) => {
     dispatch(fetchBlocksRequest());
@@ -83,3 +86,14 @@ export function expandBlocksFail(error) {
     error,
   };
 };
+
+export function initBlockModal(account) {
+  return dispatch => {
+    dispatch({
+      type: BLOCKS_INIT_MODAL,
+      account,
+    });
+
+    dispatch(openModal('BLOCK'));
+  };
+}
diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js
index e1da03745..69cf65b5a 100644
--- a/app/javascript/flavours/glitch/actions/compose.js
+++ b/app/javascript/flavours/glitch/actions/compose.js
@@ -261,7 +261,7 @@ export function uploadCompose(files) {
             progress[i] = loaded;
             dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
           },
-        }).then(({ data }) => dispatch(uploadComposeSuccess(data)));
+        }).then(({ data }) => dispatch(uploadComposeSuccess(data, f)));
       }).catch(error => dispatch(uploadComposeFail(error)));
     };
   };
@@ -316,10 +316,11 @@ export function uploadComposeProgress(loaded, total) {
   };
 };
 
-export function uploadComposeSuccess(media) {
+export function uploadComposeSuccess(media, file) {
   return {
     type: COMPOSE_UPLOAD_SUCCESS,
     media: media,
+    file: file,
     skipLoading: true,
   };
 };
diff --git a/app/javascript/flavours/glitch/actions/conversations.js b/app/javascript/flavours/glitch/actions/conversations.js
index 856f8f10f..e5c85c65d 100644
--- a/app/javascript/flavours/glitch/actions/conversations.js
+++ b/app/javascript/flavours/glitch/actions/conversations.js
@@ -15,6 +15,10 @@ export const CONVERSATIONS_UPDATE        = 'CONVERSATIONS_UPDATE';
 
 export const CONVERSATIONS_READ = 'CONVERSATIONS_READ';
 
+export const CONVERSATIONS_DELETE_REQUEST = 'CONVERSATIONS_DELETE_REQUEST';
+export const CONVERSATIONS_DELETE_SUCCESS = 'CONVERSATIONS_DELETE_SUCCESS';
+export const CONVERSATIONS_DELETE_FAIL    = 'CONVERSATIONS_DELETE_FAIL';
+
 export const mountConversations = () => ({
   type: CONVERSATIONS_MOUNT,
 });
@@ -82,3 +86,27 @@ export const updateConversations = conversation => dispatch => {
     conversation,
   });
 };
+
+export const deleteConversation = conversationId => (dispatch, getState) => {
+  dispatch(deleteConversationRequest(conversationId));
+
+  api(getState).delete(`/api/v1/conversations/${conversationId}`)
+    .then(() => dispatch(deleteConversationSuccess(conversationId)))
+    .catch(error => dispatch(deleteConversationFail(conversationId, error)));
+};
+
+export const deleteConversationRequest = id => ({
+  type: CONVERSATIONS_DELETE_REQUEST,
+  id,
+});
+
+export const deleteConversationSuccess = id => ({
+  type: CONVERSATIONS_DELETE_SUCCESS,
+  id,
+});
+
+export const deleteConversationFail = (id, error) => ({
+  type: CONVERSATIONS_DELETE_FAIL,
+  id,
+  error,
+});
diff --git a/app/javascript/flavours/glitch/actions/importer/normalizer.js b/app/javascript/flavours/glitch/actions/importer/normalizer.js
index 52d85c059..b35c4d7bd 100644
--- a/app/javascript/flavours/glitch/actions/importer/normalizer.js
+++ b/app/javascript/flavours/glitch/actions/importer/normalizer.js
@@ -71,8 +71,9 @@ export function normalizePoll(poll) {
 
   const emojiMap = makeEmojiMap(normalPoll);
 
-  normalPoll.options = poll.options.map(option => ({
+  normalPoll.options = poll.options.map((option, index) => ({
     ...option,
+    voted: poll.own_votes && poll.own_votes.includes(index),
     title_emojified: emojify(escapeTextContentForBrowser(option.title), emojiMap),
   }));
 
diff --git a/app/javascript/flavours/glitch/components/avatar_composite.js b/app/javascript/flavours/glitch/components/avatar_composite.js
index c52df043a..125b51c44 100644
--- a/app/javascript/flavours/glitch/components/avatar_composite.js
+++ b/app/javascript/flavours/glitch/components/avatar_composite.js
@@ -35,35 +35,35 @@ export default class AvatarComposite extends React.PureComponent {
 
     if (size === 2) {
       if (index === 0) {
-        right = '2px';
+        right = '1px';
       } else {
-        left = '2px';
+        left = '1px';
       }
     } else if (size === 3) {
       if (index === 0) {
-        right = '2px';
+        right = '1px';
       } else if (index > 0) {
-        left = '2px';
+        left = '1px';
       }
 
       if (index === 1) {
-        bottom = '2px';
+        bottom = '1px';
       } else if (index > 1) {
-        top = '2px';
+        top = '1px';
       }
     } else if (size === 4) {
       if (index === 0 || index === 2) {
-        right = '2px';
+        right = '1px';
       }
 
       if (index === 1 || index === 3) {
-        left = '2px';
+        left = '1px';
       }
 
       if (index < 2) {
-        bottom = '2px';
+        bottom = '1px';
       } else {
-        top = '2px';
+        top = '1px';
       }
     }
 
@@ -96,7 +96,13 @@ export default class AvatarComposite extends React.PureComponent {
 
     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))}
+        {accounts.take(4).map((account, i) => this.renderItem(account, Math.min(accounts.size, 4), i))}
+
+        {accounts.size > 4 && (
+          <span className='account__avatar-composite__label'>
+            +{accounts.size - 4}
+          </span>
+        )}
       </div>
     );
   }
diff --git a/app/javascript/flavours/glitch/components/column_back_button_slim.js b/app/javascript/flavours/glitch/components/column_back_button_slim.js
index b57e3a057..faa0c23a8 100644
--- a/app/javascript/flavours/glitch/components/column_back_button_slim.js
+++ b/app/javascript/flavours/glitch/components/column_back_button_slim.js
@@ -1,7 +1,7 @@
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import PropTypes from 'prop-types';
-import Icon from 'mastodon/components/icon';
+import Icon from 'flavours/glitch/components/icon';
 
 export default class ColumnBackButtonSlim extends React.PureComponent {
 
diff --git a/app/javascript/flavours/glitch/components/poll.js b/app/javascript/flavours/glitch/components/poll.js
index 905aa54c1..a7f9a97da 100644
--- a/app/javascript/flavours/glitch/components/poll.js
+++ b/app/javascript/flavours/glitch/components/poll.js
@@ -10,9 +10,11 @@ import spring from 'react-motion/lib/spring';
 import escapeTextContentForBrowser from 'escape-html';
 import emojify from 'flavours/glitch/util/emoji';
 import RelativeTimestamp from './relative_timestamp';
+import Icon from 'flavours/glitch/components/icon';
 
 const messages = defineMessages({
   closed: { id: 'poll.closed', defaultMessage: 'Closed' },
+  voted: { id: 'poll.voted', defaultMessage: 'You voted for this answer', description: 'Tooltip of the "voted" checkmark in polls' },
 });
 
 const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
@@ -99,10 +101,12 @@ class Poll extends ImmutablePureComponent {
   };
 
   renderOption (option, optionIndex, showResults) {
-    const { poll, disabled } = this.props;
-    const percent            = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100;
-    const leading            = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count'));
-    const active             = !!this.state.selected[`${optionIndex}`];
+    const { poll, disabled, intl } = this.props;
+    const pollVotesCount  = poll.get('voters_count') || poll.get('votes_count');
+    const percent         = pollVotesCount === 0 ? 0 : (option.get('votes_count') / pollVotesCount) * 100;
+    const leading         = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') >= other.get('votes_count'));
+    const active          = !!this.state.selected[`${optionIndex}`];
+    const voted           = option.get('voted') || (poll.get('own_votes') && poll.get('own_votes').includes(optionIndex));
 
     let titleEmojified = option.get('title_emojified');
     if (!titleEmojified) {
@@ -131,7 +135,10 @@ class Poll extends ImmutablePureComponent {
           />
 
           {!showResults && <span className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} />}
-          {showResults && <span className='poll__number'>{Math.round(percent)}%</span>}
+          {showResults && <span className='poll__number'>
+            {!!voted && <Icon id='check' className='poll__vote__mark' title={intl.formatMessage(messages.voted)} />}
+            {Math.round(percent)}%
+          </span>}
 
           <span dangerouslySetInnerHTML={{ __html: titleEmojified }} />
         </label>
@@ -151,6 +158,14 @@ class Poll extends ImmutablePureComponent {
     const showResults   = poll.get('voted') || expired;
     const disabled      = this.props.disabled || Object.entries(this.state.selected).every(item => !item);
 
+    let votesCount = null;
+
+    if (poll.get('voters_count') !== null && poll.get('voters_count') !== undefined) {
+      votesCount = <FormattedMessage id='poll.total_people' defaultMessage='{count, plural, one {# person} other {# people}}' values={{ count: poll.get('voters_count') }} />;
+    } else {
+      votesCount = <FormattedMessage id='poll.total_votes' defaultMessage='{count, plural, one {# vote} other {# votes}}' values={{ count: poll.get('votes_count') }} />;
+    }
+
     return (
       <div className='poll'>
         <ul>
@@ -160,7 +175,7 @@ class Poll extends ImmutablePureComponent {
         <div className='poll__footer'>
           {!showResults && <button className='button button-secondary' disabled={disabled} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
           {showResults && !this.props.disabled && <span><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </span>}
-          <FormattedMessage id='poll.total_votes' defaultMessage='{count, plural, one {# vote} other {# votes}}' values={{ count: poll.get('votes_count') }} />
+          {votesCount}
           {poll.get('expires_at') && <span> · {timeRemaining}</span>}
         </div>
       </div>
diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js
index 15eb4f85f..4c3555dea 100644
--- a/app/javascript/flavours/glitch/containers/status_container.js
+++ b/app/javascript/flavours/glitch/containers/status_container.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import Status from 'flavours/glitch/components/status';
 import { List as ImmutableList } from 'immutable';
@@ -18,9 +17,9 @@ import {
   pin,
   unpin,
 } from 'flavours/glitch/actions/interactions';
-import { blockAccount } from 'flavours/glitch/actions/accounts';
 import { muteStatus, unmuteStatus, deleteStatus } from 'flavours/glitch/actions/statuses';
 import { initMuteModal } from 'flavours/glitch/actions/mutes';
+import { initBlockModal } from 'flavours/glitch/actions/blocks';
 import { initReport } from 'flavours/glitch/actions/reports';
 import { openModal } from 'flavours/glitch/actions/modal';
 import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
@@ -37,10 +36,8 @@ const messages = defineMessages({
   deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
   redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
   redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' },
-  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
   replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
   replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
-  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
   unfilterConfirm: { id: 'confirmations.unfilter.confirm', defaultMessage: 'Show' },
   author: { id: 'confirmations.unfilter.author', defaultMessage: 'Author' },
   matchingFilters: { id: 'confirmations.unfilter.filters', defaultMessage: 'Matching {count, plural, one {filter} other {filters}}' },
@@ -83,6 +80,7 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
   onReply (status, router) {
     dispatch((_, getState) => {
       let state = getState();
+
       if (state.getIn(['local_settings', 'confirm_before_clearing_draft']) && state.getIn(['compose', 'text']).trim().length !== 0) {
         dispatch(openModal('CONFIRM', {
           message: intl.formatMessage(messages.replyMessage),
@@ -186,16 +184,7 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
 
   onBlock (status) {
     const account = status.get('account');
-    dispatch(openModal('CONFIRM', {
-      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
-      confirm: intl.formatMessage(messages.blockConfirm),
-      onConfirm: () => dispatch(blockAccount(account.get('id'))),
-      secondary: intl.formatMessage(messages.blockAndReport),
-      onSecondary: () => {
-        dispatch(blockAccount(account.get('id')));
-        dispatch(initReport(account, status));
-      },
-    }));
+    dispatch(initBlockModal(account));
   },
 
   onUnfilter (status, onConfirm) {
diff --git a/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
index 787a36658..fff5e097f 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
@@ -5,7 +5,6 @@ import Header from '../components/header';
 import {
   followAccount,
   unfollowAccount,
-  blockAccount,
   unblockAccount,
   unmuteAccount,
   pinAccount,
@@ -16,6 +15,7 @@ import {
   directCompose
 } from 'flavours/glitch/actions/compose';
 import { initMuteModal } from 'flavours/glitch/actions/mutes';
+import { initBlockModal } from 'flavours/glitch/actions/blocks';
 import { initReport } from 'flavours/glitch/actions/reports';
 import { openModal } from 'flavours/glitch/actions/modal';
 import { blockDomain, unblockDomain } from 'flavours/glitch/actions/domain_blocks';
@@ -25,9 +25,7 @@ import { List as ImmutableList } from 'immutable';
 
 const messages = defineMessages({
   unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
-  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
   blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
-  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
 });
 
 const makeMapStateToProps = () => {
@@ -64,16 +62,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
     if (account.getIn(['relationship', 'blocking'])) {
       dispatch(unblockAccount(account.get('id')));
     } else {
-      dispatch(openModal('CONFIRM', {
-        message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
-        confirm: intl.formatMessage(messages.blockConfirm),
-        onConfirm: () => dispatch(blockAccount(account.get('id'))),
-        secondary: intl.formatMessage(messages.blockAndReport),
-        onSecondary: () => {
-          dispatch(blockAccount(account.get('id')));
-          dispatch(initReport(account));
-        },
-      }));
+      dispatch(initBlockModal(account));
     }
   },
 
diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js
index 9ddeabe75..17487b202 100644
--- a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js
+++ b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js
@@ -2,9 +2,28 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
-import StatusContainer from 'flavours/glitch/containers/status_container';
+import StatusContent from 'flavours/glitch/components/status_content';
+import AttachmentList from 'flavours/glitch/components/attachment_list';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
+import AvatarComposite from 'flavours/glitch/components/avatar_composite';
+import Permalink from 'flavours/glitch/components/permalink';
+import IconButton from 'flavours/glitch/components/icon_button';
+import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
+import { HotKeys } from 'react-hotkeys';
 
-export default class Conversation extends ImmutablePureComponent {
+const messages = defineMessages({
+  more: { id: 'status.more', defaultMessage: 'More' },
+  open: { id: 'conversation.open', defaultMessage: 'View conversation' },
+  reply: { id: 'status.reply', defaultMessage: 'Reply' },
+  markAsRead: { id: 'conversation.mark_as_read', defaultMessage: 'Mark as read' },
+  delete: { id: 'conversation.delete', defaultMessage: 'Delete conversation' },
+  muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
+  unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
+});
+
+export default @injectIntl
+class Conversation extends ImmutablePureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -13,25 +32,61 @@ export default class Conversation extends ImmutablePureComponent {
   static propTypes = {
     conversationId: PropTypes.string.isRequired,
     accounts: ImmutablePropTypes.list.isRequired,
-    lastStatusId: PropTypes.string,
+    lastStatus: ImmutablePropTypes.map,
     unread:PropTypes.bool.isRequired,
     onMoveUp: PropTypes.func,
     onMoveDown: PropTypes.func,
     markRead: PropTypes.func.isRequired,
+    intl: PropTypes.object.isRequired,
+  };
+
+  state = {
+    isExpanded: undefined,
   };
 
+  parseClick = (e, destination) => {
+    const { router } = this.context;
+    const { lastStatus, unread, markRead } = this.props;
+    if (!router) return;
+
+    if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey)) {
+      if (destination === undefined) {
+        if (unread) {
+          markRead();
+        }
+        destination = `/statuses/${lastStatus.get('id')}`;
+      }
+      let state = {...router.history.location.state};
+      state.mastodonBackSteps = (state.mastodonBackSteps || 0) + 1;
+      router.history.push(destination, state);
+      e.preventDefault();
+    }
+  }
+
   handleClick = () => {
     if (!this.context.router) {
       return;
     }
 
-    const { lastStatusId, unread, markRead } = this.props;
+    const { lastStatus, unread, markRead } = this.props;
 
     if (unread) {
       markRead();
     }
 
-    this.context.router.history.push(`/statuses/${lastStatusId}`);
+    this.context.router.history.push(`/statuses/${lastStatus.get('id')}`);
+  }
+
+  handleMarkAsRead = () => {
+    this.props.markRead();
+  }
+
+  handleReply = () => {
+    this.props.reply(this.props.lastStatus, this.context.router.history);
+  }
+
+  handleDelete = () => {
+    this.props.delete();
   }
 
   handleHotkeyMoveUp = () => {
@@ -42,22 +97,94 @@ export default class Conversation extends ImmutablePureComponent {
     this.props.onMoveDown(this.props.conversationId);
   }
 
+  handleConversationMute = () => {
+    this.props.onMute(this.props.lastStatus);
+  }
+
+  handleShowMore = () => {
+    if (this.props.lastStatus.get('spoiler_text')) {
+      this.setExpansion(!this.state.isExpanded);
+    }
+  };
+
+  setExpansion = value => {
+    this.setState({ isExpanded: value });
+  }
+
   render () {
-    const { accounts, lastStatusId, unread } = this.props;
+    const { accounts, lastStatus, unread, intl } = this.props;
+    const { isExpanded } = this.state;
 
-    if (lastStatusId === null) {
+    if (lastStatus === null) {
       return null;
     }
 
+    const menu = [
+      { text: intl.formatMessage(messages.open), action: this.handleClick },
+      null,
+    ];
+
+    menu.push({ text: intl.formatMessage(lastStatus.get('muted') ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMute });
+
+    if (unread) {
+      menu.push({ text: intl.formatMessage(messages.markAsRead), action: this.handleMarkAsRead });
+      menu.push(null);
+    }
+
+    menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDelete });
+
+    const names = accounts.map(a => <Permalink to={`/accounts/${a.get('id')}`} href={a.get('url')} key={a.get('id')} title={a.get('acct')}><bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }} /></bdi></Permalink>).reduce((prev, cur) => [prev, ', ', cur]);
+
+    const handlers = {
+      reply: this.handleReply,
+      open: this.handleClick,
+      moveUp: this.handleHotkeyMoveUp,
+      moveDown: this.handleHotkeyMoveDown,
+      toggleHidden: this.handleShowMore,
+    };
+
+    let media = null;
+    if (lastStatus.get('media_attachments').size > 0) {
+      media = <AttachmentList compact media={lastStatus.get('media_attachments')} />;
+    }
+
     return (
-      <StatusContainer
-        id={lastStatusId}
-        unread={unread}
-        otherAccounts={accounts}
-        onMoveUp={this.handleHotkeyMoveUp}
-        onMoveDown={this.handleHotkeyMoveDown}
-        onClick={this.handleClick}
-      />
+      <HotKeys handlers={handlers}>
+        <div className='conversation focusable muted' tabIndex='0'>
+          <div className='conversation__avatar'>
+            <AvatarComposite accounts={accounts} size={48} />
+          </div>
+
+          <div className='conversation__content'>
+            <div className='conversation__content__info'>
+              <div className='conversation__content__relative-time'>
+                <RelativeTimestamp timestamp={lastStatus.get('created_at')} />
+              </div>
+
+              <div className='conversation__content__names'>
+                <FormattedMessage id='conversation.with' defaultMessage='With {names}' values={{ names: <span>{names}</span> }} />
+              </div>
+            </div>
+
+            <StatusContent
+              status={lastStatus}
+              parseClick={this.parseClick}
+              expanded={isExpanded}
+              onExpandedToggle={this.handleShowMore}
+              collapsable
+              media={media}
+            />
+
+            <div className='status__action-bar'>
+              <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.reply)} icon='reply' onClick={this.handleReply} />
+
+              <div className='status__action-bar-dropdown'>
+                <DropdownMenuContainer status={lastStatus} items={menu} icon='ellipsis-h' size={18} direction='right' title={intl.formatMessage(messages.more)} />
+              </div>
+            </div>
+          </div>
+        </div>
+      </HotKeys>
     );
   }
 
diff --git a/app/javascript/flavours/glitch/features/direct_timeline/containers/conversation_container.js b/app/javascript/flavours/glitch/features/direct_timeline/containers/conversation_container.js
index bd6f6bfb0..b15ce9f0f 100644
--- a/app/javascript/flavours/glitch/features/direct_timeline/containers/conversation_container.js
+++ b/app/javascript/flavours/glitch/features/direct_timeline/containers/conversation_container.js
@@ -1,19 +1,74 @@
 import { connect } from 'react-redux';
 import Conversation from '../components/conversation';
-import { markConversationRead } from '../../../actions/conversations';
+import { markConversationRead, deleteConversation } from 'flavours/glitch/actions/conversations';
+import { makeGetStatus } from 'flavours/glitch/selectors';
+import { replyCompose } from 'flavours/glitch/actions/compose';
+import { openModal } from 'flavours/glitch/actions/modal';
+import { muteStatus, unmuteStatus, hideStatus, revealStatus } from 'flavours/glitch/actions/statuses';
+import { defineMessages, injectIntl } from 'react-intl';
 
-const mapStateToProps = (state, { conversationId }) => {
-  const conversation = state.getIn(['conversations', 'items']).find(x => x.get('id') === conversationId);
+const messages = defineMessages({
+  replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
+  replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
+});
+
+const mapStateToProps = () => {
+  const getStatus = makeGetStatus();
+
+  return (state, { conversationId }) => {
+    const conversation = state.getIn(['conversations', 'items']).find(x => x.get('id') === conversationId);
+    const lastStatusId = conversation.get('last_status', null);
 
-  return {
-    accounts: conversation.get('accounts').map(accountId => state.getIn(['accounts', accountId], null)),
-    unread: conversation.get('unread'),
-    lastStatusId: conversation.get('last_status', null),
+    return {
+      accounts: conversation.get('accounts').map(accountId => state.getIn(['accounts', accountId], null)),
+      unread: conversation.get('unread'),
+      lastStatus: lastStatusId && getStatus(state, { id: lastStatusId }),
+    };
   };
 };
 
-const mapDispatchToProps = (dispatch, { conversationId }) => ({
-  markRead: () => dispatch(markConversationRead(conversationId)),
+const mapDispatchToProps = (dispatch, { intl, conversationId }) => ({
+
+  markRead () {
+    dispatch(markConversationRead(conversationId));
+  },
+
+  reply (status, router) {
+    dispatch((_, getState) => {
+      let state = getState();
+
+      if (state.getIn(['compose', 'text']).trim().length !== 0) {
+        dispatch(openModal('CONFIRM', {
+          message: intl.formatMessage(messages.replyMessage),
+          confirm: intl.formatMessage(messages.replyConfirm),
+          onConfirm: () => dispatch(replyCompose(status, router)),
+        }));
+      } else {
+        dispatch(replyCompose(status, router));
+      }
+    });
+  },
+
+  delete () {
+    dispatch(deleteConversation(conversationId));
+  },
+
+  onMute (status) {
+    if (status.get('muted')) {
+      dispatch(unmuteStatus(status.get('id')));
+    } else {
+      dispatch(muteStatus(status.get('id')));
+    }
+  },
+
+  onToggleHidden (status) {
+    if (status.get('hidden')) {
+      dispatch(revealStatus(status.get('id')));
+    } else {
+      dispatch(hideStatus(status.get('id')));
+    }
+  },
+
 });
 
-export default connect(mapStateToProps, mapDispatchToProps)(Conversation);
+export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(Conversation));
diff --git a/app/javascript/flavours/glitch/features/favourites/index.js b/app/javascript/flavours/glitch/features/favourites/index.js
index 5c33c8677..7afadf12e 100644
--- a/app/javascript/flavours/glitch/features/favourites/index.js
+++ b/app/javascript/flavours/glitch/features/favourites/index.js
@@ -31,7 +31,9 @@ class Favourites extends ImmutablePureComponent {
   };
 
   componentWillMount () {
-    this.props.dispatch(fetchFavourites(this.props.params.statusId));
+    if (!this.props.accountIds) {
+      this.props.dispatch(fetchFavourites(this.props.params.statusId));
+    }
   }
 
   componentWillReceiveProps (nextProps) {
diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js
index b12efa774..2bd0e6e2f 100644
--- a/app/javascript/flavours/glitch/features/followers/index.js
+++ b/app/javascript/flavours/glitch/features/followers/index.js
@@ -36,8 +36,10 @@ class Followers extends ImmutablePureComponent {
   };
 
   componentWillMount () {
-    this.props.dispatch(fetchAccount(this.props.params.accountId));
-    this.props.dispatch(fetchFollowers(this.props.params.accountId));
+    if (!this.props.accountIds) {
+      this.props.dispatch(fetchAccount(this.props.params.accountId));
+      this.props.dispatch(fetchFollowers(this.props.params.accountId));
+    }
   }
 
   componentWillReceiveProps (nextProps) {
diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js
index 9ea008e61..f03da0c94 100644
--- a/app/javascript/flavours/glitch/features/following/index.js
+++ b/app/javascript/flavours/glitch/features/following/index.js
@@ -36,8 +36,10 @@ class Following extends ImmutablePureComponent {
   };
 
   componentWillMount () {
-    this.props.dispatch(fetchAccount(this.props.params.accountId));
-    this.props.dispatch(fetchFollowing(this.props.params.accountId));
+    if (!this.props.accountIds) {
+      this.props.dispatch(fetchAccount(this.props.params.accountId));
+      this.props.dispatch(fetchFollowing(this.props.params.accountId));
+    }
   }
 
   componentWillReceiveProps (nextProps) {
diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js
index 68b5209dc..a5095fbd9 100644
--- a/app/javascript/flavours/glitch/features/getting_started/index.js
+++ b/app/javascript/flavours/glitch/features/getting_started/index.js
@@ -104,16 +104,14 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2);
   }
 
   componentDidMount () {
-    const { myAccount, fetchFollowRequests, multiColumn } = this.props;
+    const { fetchFollowRequests, multiColumn } = this.props;
 
     if (!multiColumn && window.innerWidth >= NAVIGATION_PANEL_BREAKPOINT) {
       this.context.router.history.replace('/timelines/home');
       return;
     }
 
-    if (myAccount.get('locked')) {
-      fetchFollowRequests();
-    }
+    fetchFollowRequests();
   }
 
   render () {
@@ -148,7 +146,7 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2);
       navItems.push(<ColumnLink key='5' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />);
     }
 
-    if (myAccount.get('locked')) {
+    if (myAccount.get('locked') || unreadFollowRequests > 0) {
       navItems.push(<ColumnLink key='6' icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
     }
 
diff --git a/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js b/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js
index 356ca4721..6118305d6 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/filter_bar.js
@@ -64,7 +64,7 @@ class FilterBar extends React.PureComponent {
           onClick={this.onClick('mention')}
           title={intl.formatMessage(tooltips.mentions)}
         >
-          <Icon id='at' fixedWidth />
+          <Icon id='reply-all' fixedWidth />
         </button>
         <button
           className={selectedFilter === 'favourite' ? 'active' : ''}
diff --git a/app/javascript/flavours/glitch/features/reblogs/index.js b/app/javascript/flavours/glitch/features/reblogs/index.js
index 1fc26b0d7..a8e9db7f5 100644
--- a/app/javascript/flavours/glitch/features/reblogs/index.js
+++ b/app/javascript/flavours/glitch/features/reblogs/index.js
@@ -31,7 +31,9 @@ class Reblogs extends ImmutablePureComponent {
   };
 
   componentWillMount () {
-    this.props.dispatch(fetchReblogs(this.props.params.statusId));
+    if (!this.props.accountIds) {
+      this.props.dispatch(fetchReblogs(this.props.params.statusId));
+    }
   }
 
   componentWillReceiveProps(nextProps) {
diff --git a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js
index e6c390537..e71803328 100644
--- a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js
+++ b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import DetailedStatus from '../components/detailed_status';
 import { makeGetStatus } from 'flavours/glitch/selectors';
@@ -15,7 +14,6 @@ import {
   pin,
   unpin,
 } from 'flavours/glitch/actions/interactions';
-import { blockAccount } from 'flavours/glitch/actions/accounts';
 import {
   muteStatus,
   unmuteStatus,
@@ -24,9 +22,10 @@ import {
   revealStatus,
 } from 'flavours/glitch/actions/statuses';
 import { initMuteModal } from 'flavours/glitch/actions/mutes';
+import { initBlockModal } from 'flavours/glitch/actions/blocks';
 import { initReport } from 'flavours/glitch/actions/reports';
 import { openModal } from 'flavours/glitch/actions/modal';
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { defineMessages, injectIntl } from 'react-intl';
 import { boostModal, deleteModal } from 'flavours/glitch/util/initial_state';
 import { showAlertForError } from 'flavours/glitch/actions/alerts';
 
@@ -35,10 +34,8 @@ const messages = defineMessages({
   deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
   redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
   redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: '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.' },
-  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
   replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
   replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
-  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
 });
 
 const makeMapStateToProps = () => {
@@ -139,16 +136,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
 
   onBlock (status) {
     const account = status.get('account');
-    dispatch(openModal('CONFIRM', {
-      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
-      confirm: intl.formatMessage(messages.blockConfirm),
-      onConfirm: () => dispatch(blockAccount(account.get('id'))),
-      secondary: intl.formatMessage(messages.blockAndReport),
-      onSecondary: () => {
-        dispatch(blockAccount(account.get('id')));
-        dispatch(initReport(account, status));
-      },
-    }));
+    dispatch(initBlockModal(account));
   },
 
   onReport (status) {
diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js
index e91ab5f3a..dd17823ad 100644
--- a/app/javascript/flavours/glitch/features/status/index.js
+++ b/app/javascript/flavours/glitch/features/status/index.js
@@ -26,9 +26,9 @@ import {
   directCompose,
 } from 'flavours/glitch/actions/compose';
 import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
-import { blockAccount } from 'flavours/glitch/actions/accounts';
 import { muteStatus, unmuteStatus, deleteStatus } from 'flavours/glitch/actions/statuses';
 import { initMuteModal } from 'flavours/glitch/actions/mutes';
+import { initBlockModal } from 'flavours/glitch/actions/blocks';
 import { initReport } from 'flavours/glitch/actions/reports';
 import { makeGetStatus } from 'flavours/glitch/selectors';
 import { ScrollContainer } from 'react-router-scroll-4';
@@ -36,7 +36,7 @@ import ColumnBackButton from 'flavours/glitch/components/column_back_button';
 import ColumnHeader from '../../components/column_header';
 import StatusContainer from 'flavours/glitch/containers/status_container';
 import { openModal } from 'flavours/glitch/actions/modal';
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { HotKeys } from 'react-hotkeys';
 import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/util/initial_state';
@@ -50,13 +50,11 @@ const messages = defineMessages({
   deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
   redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
   redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' },
-  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
   revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },
   hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },
   detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' },
   replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
   replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
-  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
   tootHeading: { id: 'column.toot', defaultMessage: 'Toots and replies' },
 });
 
@@ -339,19 +337,9 @@ class Status extends ImmutablePureComponent {
   }
 
   handleBlockClick = (status) => {
-    const { dispatch, intl } = this.props;
+    const { dispatch } = this.props;
     const account = status.get('account');
-
-    dispatch(openModal('CONFIRM', {
-      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
-      confirm: intl.formatMessage(messages.blockConfirm),
-      onConfirm: () => dispatch(blockAccount(account.get('id'))),
-      secondary: intl.formatMessage(messages.blockAndReport),
-      onSecondary: () => {
-        dispatch(blockAccount(account.get('id')));
-        dispatch(initReport(account, status));
-      },
-    }));
+    dispatch(initBlockModal(account));
   }
 
   handleReport = (status) => {
diff --git a/app/javascript/flavours/glitch/features/ui/components/block_modal.js b/app/javascript/flavours/glitch/features/ui/components/block_modal.js
new file mode 100644
index 000000000..a07baeaa6
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/ui/components/block_modal.js
@@ -0,0 +1,103 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { injectIntl, FormattedMessage } from 'react-intl';
+import { makeGetAccount } from '../../../selectors';
+import Button from '../../../components/button';
+import { closeModal } from '../../../actions/modal';
+import { blockAccount } from '../../../actions/accounts';
+import { initReport } from '../../../actions/reports';
+
+
+const makeMapStateToProps = () => {
+  const getAccount = makeGetAccount();
+
+  const mapStateToProps = state => ({
+    account: getAccount(state, state.getIn(['blocks', 'new', 'account_id'])),
+  });
+
+  return mapStateToProps;
+};
+
+const mapDispatchToProps = dispatch => {
+  return {
+    onConfirm(account) {
+      dispatch(blockAccount(account.get('id')));
+    },
+
+    onBlockAndReport(account) {
+      dispatch(blockAccount(account.get('id')));
+      dispatch(initReport(account));
+    },
+
+    onClose() {
+      dispatch(closeModal());
+    },
+  };
+};
+
+export default @connect(makeMapStateToProps, mapDispatchToProps)
+@injectIntl
+class BlockModal extends React.PureComponent {
+
+  static propTypes = {
+    account: PropTypes.object.isRequired,
+    onClose: PropTypes.func.isRequired,
+    onBlockAndReport: PropTypes.func.isRequired,
+    onConfirm: PropTypes.func.isRequired,
+    intl: PropTypes.object.isRequired,
+  };
+
+  componentDidMount() {
+    this.button.focus();
+  }
+
+  handleClick = () => {
+    this.props.onClose();
+    this.props.onConfirm(this.props.account);
+  }
+
+  handleSecondary = () => {
+    this.props.onClose();
+    this.props.onBlockAndReport(this.props.account);
+  }
+
+  handleCancel = () => {
+    this.props.onClose();
+  }
+
+  setRef = (c) => {
+    this.button = c;
+  }
+
+  render () {
+    const { account } = this.props;
+
+    return (
+      <div className='modal-root__modal block-modal'>
+        <div className='block-modal__container'>
+          <p>
+            <FormattedMessage
+              id='confirmations.block.message'
+              defaultMessage='Are you sure you want to block {name}?'
+              values={{ name: <strong>@{account.get('acct')}</strong> }}
+            />
+          </p>
+        </div>
+
+        <div className='block-modal__action-bar'>
+          <Button onClick={this.handleCancel} className='block-modal__cancel-button'>
+            <FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
+          </Button>
+          <Button onClick={this.handleSecondary} className='confirmation-modal__secondary-button'>
+            <FormattedMessage id='confirmations.block.block_and_report' defaultMessage='Block & Report' />
+          </Button>
+          <Button onClick={this.handleClick} ref={this.setRef}>
+            <FormattedMessage id='confirmations.block.confirm' defaultMessage='Block' />
+          </Button>
+        </div>
+      </div>
+    );
+  }
+
+}
diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
index 8bded391a..d5c9e66ae 100644
--- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.js
@@ -173,7 +173,17 @@ class FocalPointModal extends ImmutablePureComponent {
         langPath: `${assetHost}/ocr/lang-data`,
       });
 
-      worker.recognize(media.get('url'))
+      let media_url = media.get('file');
+
+      if (window.URL && URL.createObjectURL) {
+        try {
+          media_url = URL.createObjectURL(media.get('file'));
+        } catch (error) {
+          console.error(error);
+        }
+      }
+
+      worker.recognize(media_url)
         .progress(({ progress }) => this.setState({ progress }))
         .finally(() => worker.terminate())
         .then(({ text }) => this.setState({ description: removeExtraLineBreaks(text), dirty: true, detecting: false }))
diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js
index 303e05db6..0941ce9c8 100644
--- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js
+++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js
@@ -15,6 +15,7 @@ import FocalPointModal from './focal_point_modal';
 import {
   OnboardingModal,
   MuteModal,
+  BlockModal,
   ReportModal,
   SettingsModal,
   EmbedModal,
@@ -32,6 +33,7 @@ const MODAL_COMPONENTS = {
   'DOODLE': () => Promise.resolve({ default: DoodleModal }),
   'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
   'MUTE': MuteModal,
+  'BLOCK': BlockModal,
   'REPORT': ReportModal,
   'SETTINGS': SettingsModal,
   'ACTIONS': () => Promise.resolve({ default: ActionsModal }),
diff --git a/app/javascript/flavours/glitch/features/ui/components/mute_modal.js b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js
index 3492eca69..dec6413c3 100644
--- a/app/javascript/flavours/glitch/features/ui/components/mute_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js
@@ -11,7 +11,6 @@ import { toggleHideNotifications } from 'flavours/glitch/actions/mutes';
 
 const mapStateToProps = state => {
   return {
-    isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
     account: state.getIn(['mutes', 'new', 'account']),
     notifications: state.getIn(['mutes', 'new', 'notifications']),
   };
@@ -38,7 +37,6 @@ export default @connect(mapStateToProps, mapDispatchToProps)
 class MuteModal extends React.PureComponent {
 
   static propTypes = {
-    isSubmitting: PropTypes.bool.isRequired,
     account: PropTypes.object.isRequired,
     notifications: PropTypes.bool.isRequired,
     onClose: PropTypes.func.isRequired,
@@ -81,11 +79,16 @@ class MuteModal extends React.PureComponent {
               values={{ name: <strong>@{account.get('acct')}</strong> }}
             />
           </p>
-          <div>
-            <label htmlFor='mute-modal__hide-notifications-checkbox'>
+          <p className='mute-modal__explanation'>
+            <FormattedMessage
+              id='confirmations.mute.explanation'
+              defaultMessage='This will hide posts from them and posts mentioning them, but it will still allow them to see your posts follow you.'
+            />
+          </p>
+          <div className='setting-toggle'>
+            <Toggle id='mute-modal__hide-notifications-checkbox' checked={notifications} onChange={this.toggleNotifications} />
+            <label className='setting-toggle__label' htmlFor='mute-modal__hide-notifications-checkbox'>
               <FormattedMessage id='mute_modal.hide_notifications' defaultMessage='Hide notifications from this user?' />
-              {' '}
-              <Toggle id='mute-modal__hide-notifications-checkbox' checked={notifications} onChange={this.toggleNotifications} />
             </label>
           </div>
         </div>
diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js
index 019de2167..5a15830df 100644
--- a/app/javascript/flavours/glitch/packs/public.js
+++ b/app/javascript/flavours/glitch/packs/public.js
@@ -114,6 +114,16 @@ function main() {
       this.parentElement.parentElement.nextElementSibling.classList.toggle('hidden');
     });
   });
+
+  delegate(document, '.sidebar__toggle__icon', 'click', () => {
+    const target = document.querySelector('.sidebar ul');
+
+    if (target.style.display === 'block') {
+      target.style.display = 'none';
+    } else {
+      target.style.display = 'block';
+    }
+  });
 }
 
 loadPolyfills().then(main).catch(error => {
diff --git a/app/javascript/flavours/glitch/packs/settings.js b/app/javascript/flavours/glitch/packs/settings.js
new file mode 100644
index 000000000..b32f38226
--- /dev/null
+++ b/app/javascript/flavours/glitch/packs/settings.js
@@ -0,0 +1,20 @@
+import loadPolyfills from 'flavours/glitch/util/load_polyfills';
+import ready from 'flavours/glitch/util/ready';
+
+function main() {
+  const { delegate } = require('rails-ujs');
+
+  delegate(document, '.sidebar__toggle__icon', 'click', () => {
+    const target = document.querySelector('.sidebar ul');
+
+    if (target.style.display === 'block') {
+      target.style.display = 'none';
+    } else {
+      target.style.display = 'block';
+    }
+  });
+}
+
+loadPolyfills().then(main).catch(error => {
+  console.error(error);
+});
diff --git a/app/javascript/flavours/glitch/reducers/blocks.js b/app/javascript/flavours/glitch/reducers/blocks.js
new file mode 100644
index 000000000..1b6507163
--- /dev/null
+++ b/app/javascript/flavours/glitch/reducers/blocks.js
@@ -0,0 +1,22 @@
+import Immutable from 'immutable';
+
+import {
+  BLOCKS_INIT_MODAL,
+} from '../actions/blocks';
+
+const initialState = Immutable.Map({
+  new: Immutable.Map({
+    account_id: null,
+  }),
+});
+
+export default function mutes(state = initialState, action) {
+  switch (action.type) {
+  case BLOCKS_INIT_MODAL:
+    return state.withMutations((state) => {
+      state.setIn(['new', 'account_id'], action.account.get('id'));
+    });
+  default:
+    return state;
+  }
+}
diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js
index adad205c0..17ce5de3c 100644
--- a/app/javascript/flavours/glitch/reducers/compose.js
+++ b/app/javascript/flavours/glitch/reducers/compose.js
@@ -190,10 +190,13 @@ function continueThread (state, status) {
   });
 }
 
-function appendMedia(state, media) {
+function appendMedia(state, media, file) {
   const prevSize = state.get('media_attachments').size;
 
   return state.withMutations(map => {
+    if (media.get('type') === 'image') {
+      media = media.set('file', file);
+    }
     map.update('media_attachments', list => list.push(media));
     map.set('is_uploading', false);
     map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
@@ -422,7 +425,7 @@ export default function compose(state = initialState, action) {
   case COMPOSE_UPLOAD_REQUEST:
     return state.set('is_uploading', true);
   case COMPOSE_UPLOAD_SUCCESS:
-    return appendMedia(state, fromJS(action.media));
+    return appendMedia(state, fromJS(action.media), action.file);
   case COMPOSE_UPLOAD_FAIL:
     return state.set('is_uploading', false);
   case COMPOSE_UPLOAD_UNDO:
diff --git a/app/javascript/flavours/glitch/reducers/index.js b/app/javascript/flavours/glitch/reducers/index.js
index b03590194..7dbca3a29 100644
--- a/app/javascript/flavours/glitch/reducers/index.js
+++ b/app/javascript/flavours/glitch/reducers/index.js
@@ -16,6 +16,7 @@ import local_settings from './local_settings';
 import push_notifications from './push_notifications';
 import status_lists from './status_lists';
 import mutes from './mutes';
+import blocks from './blocks';
 import reports from './reports';
 import contexts from './contexts';
 import compose from './compose';
@@ -53,6 +54,7 @@ const reducers = {
   local_settings,
   push_notifications,
   mutes,
+  blocks,
   reports,
   contexts,
   compose,
diff --git a/app/javascript/flavours/glitch/reducers/mutes.js b/app/javascript/flavours/glitch/reducers/mutes.js
index 8f52a7704..7111bb710 100644
--- a/app/javascript/flavours/glitch/reducers/mutes.js
+++ b/app/javascript/flavours/glitch/reducers/mutes.js
@@ -7,7 +7,6 @@ import {
 
 const initialState = Immutable.Map({
   new: Immutable.Map({
-    isSubmitting: false,
     account: null,
     notifications: true,
   }),
@@ -17,7 +16,6 @@ export default function mutes(state = initialState, action) {
   switch (action.type) {
   case MUTES_INIT_MODAL:
     return state.withMutations((state) => {
-      state.setIn(['new', 'isSubmitting'], false);
       state.setIn(['new', 'account'], action.account);
       state.setIn(['new', 'notifications'], true);
     });
diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js
index 8dc7a4aba..8d5c6785c 100644
--- a/app/javascript/flavours/glitch/reducers/notifications.js
+++ b/app/javascript/flavours/glitch/reducers/notifications.js
@@ -52,7 +52,7 @@ const notificationToMap = (state, notification) => ImmutableMap({
 const normalizeNotification = (state, notification, usePendingItems) => {
   const top = !shouldCountUnreadNotifications(state);
 
-  if (usePendingItems || !top || !state.get('pendingItems').isEmpty()) {
+  if (usePendingItems || !state.get('pendingItems').isEmpty()) {
     return state.update('pendingItems', list => list.unshift(notificationToMap(state, notification))).update('unread', unread => unread + 1);
   }
 
@@ -82,7 +82,7 @@ const expandNormalizedNotifications = (state, notifications, next, isLoadingRece
 
   return state.withMutations(mutable => {
     if (!items.isEmpty()) {
-      usePendingItems = isLoadingRecent && (usePendingItems || !mutable.get('top') || !mutable.get('pendingItems').isEmpty());
+      usePendingItems = isLoadingRecent && (usePendingItems || !mutable.get('pendingItems').isEmpty());
 
       mutable.update(usePendingItems ? 'pendingItems' : 'items', list => {
         const lastIndex = 1 + list.findLastIndex(
diff --git a/app/javascript/flavours/glitch/reducers/timelines.js b/app/javascript/flavours/glitch/reducers/timelines.js
index e6bef18e9..df88a6c23 100644
--- a/app/javascript/flavours/glitch/reducers/timelines.js
+++ b/app/javascript/flavours/glitch/reducers/timelines.js
@@ -40,7 +40,8 @@ const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, is
     if (timeline.endsWith(':pinned')) {
       mMap.set('items', statuses.map(status => status.get('id')));
     } else if (!statuses.isEmpty()) {
-      usePendingItems = isLoadingRecent && (usePendingItems || !mMap.get('top') || !mMap.get('pendingItems').isEmpty());
+      usePendingItems = isLoadingRecent && (usePendingItems || !mMap.get('pendingItems').isEmpty());
+
       mMap.update(usePendingItems ? 'pendingItems' : 'items', ImmutableList(), oldIds => {
         const newIds = statuses.map(status => status.get('id'));
         const lastIndex = oldIds.findLastIndex(id => id !== null && compareId(id, newIds.last()) >= 0) + 1;
@@ -62,7 +63,7 @@ const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, is
 const updateTimeline = (state, timeline, status, usePendingItems) => {
   const top = state.getIn([timeline, 'top']);
 
-  if (usePendingItems || !top || !state.getIn([timeline, 'pendingItems']).isEmpty()) {
+  if (usePendingItems || !state.getIn([timeline, 'pendingItems']).isEmpty()) {
     if (state.getIn([timeline, 'pendingItems'], ImmutableList()).includes(status.get('id')) || state.getIn([timeline, 'items'], ImmutableList()).includes(status.get('id'))) {
       return state;
     }
diff --git a/app/javascript/flavours/glitch/styles/_mixins.scss b/app/javascript/flavours/glitch/styles/_mixins.scss
index d542b1083..088b41e76 100644
--- a/app/javascript/flavours/glitch/styles/_mixins.scss
+++ b/app/javascript/flavours/glitch/styles/_mixins.scss
@@ -62,24 +62,6 @@
   color: $darker-text-color;
   font-size: 14px;
   margin: 0;
-
-  &::-moz-focus-inner {
-    border: 0;
-  }
-
-  &::-moz-focus-inner,
-  &:focus,
-  &:active {
-    outline: 0 !important;
-  }
-
-  &:focus {
-    background: lighten($ui-base-color, 4%);
-  }
-
-  @media screen and (max-width: 600px) {
-    font-size: 16px;
-  }
 }
 
 @mixin search-popout() {
diff --git a/app/javascript/flavours/glitch/styles/about.scss b/app/javascript/flavours/glitch/styles/about.scss
index 0e910693d..7c129674d 100644
--- a/app/javascript/flavours/glitch/styles/about.scss
+++ b/app/javascript/flavours/glitch/styles/about.scss
@@ -17,109 +17,102 @@ $small-breakpoint: 960px;
 
 .rich-formatting {
   font-family: $font-sans-serif, sans-serif;
-  font-size: 16px;
+  font-size: 14px;
   font-weight: 400;
-  font-size: 16px;
-  line-height: 30px;
+  line-height: 1.7;
+  word-wrap: break-word;
   color: $darker-text-color;
-  padding-right: 10px;
 
   a {
     color: $highlight-text-color;
     text-decoration: underline;
+
+    &:hover,
+    &:focus,
+    &:active {
+      text-decoration: none;
+    }
   }
 
   p,
   li {
-    font-family: $font-sans-serif, sans-serif;
-    font-size: 16px;
-    font-weight: 400;
-    font-size: 16px;
-    line-height: 30px;
-    margin-bottom: 12px;
     color: $darker-text-color;
+  }
 
-    a {
-      color: $highlight-text-color;
-      text-decoration: underline;
-    }
+  p {
+    margin-top: 0;
+    margin-bottom: .85em;
 
     &:last-child {
       margin-bottom: 0;
     }
   }
 
-  strong,
-  em {
+  strong {
     font-weight: 700;
-    color: lighten($darker-text-color, 10%);
+    color: $secondary-text-color;
   }
 
-  h1 {
-    font-family: $font-display, sans-serif;
-    font-size: 26px;
-    line-height: 30px;
-    font-weight: 500;
-    margin-bottom: 20px;
+  em {
+    font-style: italic;
     color: $secondary-text-color;
+  }
 
-    small {
-      font-family: $font-sans-serif, sans-serif;
-      display: block;
-      font-size: 18px;
-      font-weight: 400;
-      color: lighten($darker-text-color, 10%);
-    }
+  code {
+    font-size: 0.85em;
+    background: darken($ui-base-color, 8%);
+    border-radius: 4px;
+    padding: 0.2em 0.3em;
   }
 
-  h2 {
+  h1,
+  h2,
+  h3,
+  h4,
+  h5,
+  h6 {
     font-family: $font-display, sans-serif;
-    font-size: 22px;
-    line-height: 26px;
+    margin-top: 1.275em;
+    margin-bottom: .85em;
     font-weight: 500;
-    margin-bottom: 20px;
     color: $secondary-text-color;
   }
 
+  h1 {
+    font-size: 2em;
+  }
+
+  h2 {
+    font-size: 1.75em;
+  }
+
   h3 {
-    font-family: $font-display, sans-serif;
-    font-size: 18px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
+    font-size: 1.5em;
   }
 
   h4 {
-    font-family: $font-display, sans-serif;
-    font-size: 16px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
+    font-size: 1.25em;
   }
 
-  h5 {
-    font-family: $font-display, sans-serif;
-    font-size: 14px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
+  h5,
+  h6 {
+    font-size: 1em;
   }
 
-  h6 {
-    font-family: $font-display, sans-serif;
-    font-size: 12px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
+  ul {
+    list-style: disc;
+  }
+
+  ol {
+    list-style: decimal;
   }
 
   ul,
   ol {
-    margin-left: 20px;
+    margin: 0;
+    padding: 0;
+    padding-left: 2em;
+    margin-bottom: 0.85em;
 
     &[type='a'] {
       list-style-type: lower-alpha;
@@ -130,31 +123,63 @@ $small-breakpoint: 960px;
     }
   }
 
-  ul {
-    list-style: disc;
-  }
-
-  ol {
-    list-style: decimal;
-  }
-
-  li > ol,
-  li > ul {
-    margin-top: 6px;
-  }
-
   hr {
     width: 100%;
     height: 0;
     border: 0;
-    border-bottom: 1px solid rgba($ui-base-lighter-color, .6);
-    margin: 20px 0;
+    border-bottom: 1px solid lighten($ui-base-color, 4%);
+    margin: 1.7em 0;
 
     &.spacer {
       height: 1px;
       border: 0;
     }
   }
+
+  table {
+    width: 100%;
+    border-collapse: collapse;
+    break-inside: auto;
+    margin-top: 24px;
+    margin-bottom: 32px;
+
+    thead tr,
+    tbody tr {
+      break-after: auto;
+      break-inside: avoid;
+      border-bottom: 1px solid lighten($ui-base-color, 4%);
+      font-size: 1em;
+      line-height: 1.625;
+      font-weight: 400;
+      text-align: left;
+      color: $darker-text-color;
+    }
+
+    thead tr {
+      border-bottom-width: 2px;
+      line-height: 1.5;
+      font-weight: 500;
+      color: $dark-text-color;
+    }
+
+    th,
+    td {
+      padding: 8px;
+      align-self: start;
+      align-items: start;
+
+      &.nowrap {
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        width: 25%;
+      }
+    }
+  }
+
+  & > :first-child {
+    margin-top: 0;
+  }
 }
 
 .information-board {
@@ -418,7 +443,7 @@ $small-breakpoint: 960px;
   }
 
   &__call-to-action {
-    background: darken($ui-base-color, 4%);
+    background: $ui-base-color;
     border-radius: 4px;
     padding: 25px 40px;
     overflow: hidden;
diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss
index 089ae68c0..1d25d0129 100644
--- a/app/javascript/flavours/glitch/styles/admin.scss
+++ b/app/javascript/flavours/glitch/styles/admin.scss
@@ -5,21 +5,66 @@ $content-width: 840px;
 .admin-wrapper {
   display: flex;
   justify-content: center;
-  height: 100%;
+  width: 100%;
+  min-height: 100vh;
 
   .sidebar-wrapper {
-    flex: 1 1 $sidebar-width;
-    height: 100%;
-    background: $ui-base-color;
-    display: flex;
-    justify-content: flex-end;
+    min-height: 100vh;
+    overflow: hidden;
+    pointer-events: none;
+    flex: 1 1 auto;
+
+    &__inner {
+      display: flex;
+      justify-content: flex-end;
+      background: $ui-base-color;
+      height: 100%;
+    }
   }
 
   .sidebar {
     width: $sidebar-width;
-    height: 100%;
     padding: 0;
-    overflow-y: auto;
+    pointer-events: auto;
+
+    &__toggle {
+      display: none;
+      background: lighten($ui-base-color, 8%);
+      height: 48px;
+
+      &__logo {
+        flex: 1 1 auto;
+
+        a {
+          display: inline-block;
+          padding: 15px;
+        }
+
+        svg {
+          fill: $primary-text-color;
+          height: 20px;
+          position: relative;
+          bottom: -2px;
+        }
+      }
+
+      &__icon {
+        display: block;
+        color: $darker-text-color;
+        text-decoration: none;
+        flex: 0 0 auto;
+        font-size: 20px;
+        padding: 15px;
+      }
+
+      a {
+        &:hover,
+        &:focus,
+        &:active {
+          background: lighten($ui-base-color, 12%);
+        }
+      }
+    }
 
     .logo {
       display: block;
@@ -52,6 +97,9 @@ $content-width: 840px;
         transition: all 200ms linear;
         transition-property: color, background-color;
         border-radius: 4px 0 0 4px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
 
         i.fa {
           margin-right: 5px;
@@ -99,12 +147,30 @@ $content-width: 840px;
   }
 
   .content-wrapper {
-    flex: 2 1 $content-width;
-    overflow: auto;
+    box-sizing: border-box;
+    width: 100%;
+    max-width: $content-width;
+    flex: 1 1 auto;
+  }
+
+  @media screen and (max-width: $content-width + $sidebar-width) {
+    .sidebar-wrapper--empty {
+      display: none;
+    }
+
+    .sidebar-wrapper {
+      width: $sidebar-width;
+      flex: 0 0 auto;
+    }
+  }
+
+  @media screen and (max-width: $no-columns-breakpoint) {
+    .sidebar-wrapper {
+      width: 100%;
+    }
   }
 
   .content {
-    max-width: $content-width;
     padding: 20px 15px;
     padding-top: 60px;
     padding-left: 25px;
@@ -123,6 +189,12 @@ $content-width: 840px;
       padding-bottom: 40px;
       border-bottom: 1px solid lighten($ui-base-color, 8%);
       margin-bottom: 40px;
+
+      @media screen and (max-width: $no-columns-breakpoint) {
+        border-bottom: 0;
+        padding-bottom: 0;
+        font-weight: 700;
+      }
     }
 
     h3 {
@@ -147,7 +219,7 @@ $content-width: 840px;
       font-size: 16px;
       color: $secondary-text-color;
       line-height: 28px;
-      font-weight: 400;
+      font-weight: 500;
     }
 
     .fields-group h6 {
@@ -176,7 +248,7 @@ $content-width: 840px;
 
     & > p {
       font-size: 14px;
-      line-height: 18px;
+      line-height: 21px;
       color: $secondary-text-color;
       margin-bottom: 20px;
 
@@ -204,49 +276,86 @@ $content-width: 840px;
         border: 0;
       }
     }
-
-    .muted-hint {
-      color: $darker-text-color;
-
-      a {
-        color: $highlight-text-color;
-      }
-    }
-
-    .positive-hint {
-      color: $valid-value-color;
-      font-weight: 500;
-    }
-
-    .negative-hint {
-      color: $error-value-color;
-      font-weight: 500;
-    }
-
-    .neutral-hint {
-      color: $dark-text-color;
-      font-weight: 500;
-    }
   }
 
   @media screen and (max-width: $no-columns-breakpoint) {
     display: block;
-    overflow-y: auto;
-    -webkit-overflow-scrolling: touch;
 
-    .sidebar-wrapper,
-    .content-wrapper {
-      flex: 0 0 auto;
-      height: auto;
-      overflow: initial;
+    .sidebar-wrapper {
+      min-height: 0;
     }
 
     .sidebar {
       width: 100%;
       padding: 0;
       height: auto;
+
+      &__toggle {
+        display: flex;
+      }
+
+      & > ul {
+        display: none;
+      }
+
+      ul a,
+      ul ul a {
+        border-radius: 0;
+        border-bottom: 1px solid lighten($ui-base-color, 4%);
+        transition: none;
+
+        &:hover {
+          transition: none;
+        }
+      }
+
+      ul ul {
+        border-radius: 0;
+      }
+
+      ul .simple-navigation-active-leaf a {
+        border-bottom-color: $ui-highlight-color;
+      }
+    }
+  }
+}
+
+hr.spacer {
+  width: 100%;
+  border: 0;
+  margin: 20px 0;
+  height: 1px;
+}
+
+body,
+.admin-wrapper .content {
+  .muted-hint {
+    color: $darker-text-color;
+
+    a {
+      color: $highlight-text-color;
     }
   }
+
+  .positive-hint {
+    color: $valid-value-color;
+    font-weight: 500;
+  }
+
+  .negative-hint {
+    color: $error-value-color;
+    font-weight: 500;
+  }
+
+  .neutral-hint {
+    color: $dark-text-color;
+    font-weight: 500;
+  }
+
+  .warning-hint {
+    color: $gold-star;
+    font-weight: 500;
+  }
 }
 
 .filters {
@@ -255,10 +364,10 @@ $content-width: 840px;
 
   .filter-subset {
     flex: 0 0 auto;
-    margin: 0 40px 10px 0;
+    margin: 0 40px 20px 0;
 
     &:last-child {
-      margin-bottom: 20px;
+      margin-bottom: 30px;
     }
 
     ul {
diff --git a/app/javascript/flavours/glitch/styles/basics.scss b/app/javascript/flavours/glitch/styles/basics.scss
index 4de3955a6..64e543b78 100644
--- a/app/javascript/flavours/glitch/styles/basics.scss
+++ b/app/javascript/flavours/glitch/styles/basics.scss
@@ -74,9 +74,6 @@ body {
 
   &.admin {
     background: darken($ui-base-color, 4%);
-    position: fixed;
-    width: 100%;
-    height: 100%;
     padding: 0;
   }
 
diff --git a/app/javascript/flavours/glitch/styles/components/accounts.scss b/app/javascript/flavours/glitch/styles/components/accounts.scss
index dc49e083c..5be4da48a 100644
--- a/app/javascript/flavours/glitch/styles/components/accounts.scss
+++ b/app/javascript/flavours/glitch/styles/components/accounts.scss
@@ -50,6 +50,8 @@
   &-composite {
     @include avatar-radius;
     overflow: hidden;
+    position: relative;
+    cursor: default;
 
     & div {
       @include avatar-radius;
@@ -57,6 +59,18 @@
       position: relative;
       box-sizing: border-box;
     }
+
+    &__label {
+      display: block;
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      color: $primary-text-color;
+      text-shadow: 1px 1px 2px $base-shadow-color;
+      font-weight: 700;
+      font-size: 15px;
+    }
   }
 }
 
@@ -245,6 +259,28 @@
   .column-select {
     &__control {
       @include search-input();
+
+      &::placeholder {
+        color: lighten($darker-text-color, 4%);
+      }
+
+      &::-moz-focus-inner {
+        border: 0;
+      }
+
+      &::-moz-focus-inner,
+      &:focus,
+      &:active {
+        outline: 0 !important;
+      }
+
+      &:focus {
+        background: lighten($ui-base-color, 4%);
+      }
+
+      @media screen and (max-width: 600px) {
+        font-size: 16px;
+      }
     }
 
     &__placeholder {
diff --git a/app/javascript/flavours/glitch/styles/components/composer.scss b/app/javascript/flavours/glitch/styles/components/composer.scss
index 656615f4f..436974919 100644
--- a/app/javascript/flavours/glitch/styles/components/composer.scss
+++ b/app/javascript/flavours/glitch/styles/components/composer.scss
@@ -44,6 +44,10 @@
     font-family: inherit;
     resize: vertical;
 
+    &::placeholder {
+      color: $dark-text-color;
+    }
+
     &:focus { outline: 0 }
     @include single-column('screen and (max-width: 630px)') { font-size: 16px }
   }
@@ -263,6 +267,10 @@
       resize: none;
       scrollbar-color: initial;
 
+      &::placeholder {
+        color: $dark-text-color;
+      }
+
       &::-webkit-scrollbar {
         all: unset;
       }
diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss
index 97c525565..848ef78df 100644
--- a/app/javascript/flavours/glitch/styles/components/index.scss
+++ b/app/javascript/flavours/glitch/styles/components/index.scss
@@ -1433,49 +1433,68 @@
   height: 1em;
 }
 
-.layout-toggle {
+.conversation {
   display: flex;
+  border-bottom: 1px solid lighten($ui-base-color, 8%);
   padding: 5px;
+  padding-bottom: 0;
 
-  button {
-    box-sizing: border-box;
-    flex: 0 0 50%;
-    background: transparent;
-    padding: 5px;
-    border: 0;
-    position: relative;
+  &:focus {
+    background: lighten($ui-base-color, 2%);
+    outline: 0;
+  }
 
-    &:hover,
-    &:focus,
-    &:active {
-      svg path:first-child {
-        fill: lighten($ui-base-color, 16%);
-      }
-    }
+  &__avatar {
+    flex: 0 0 auto;
+    padding: 10px;
+    padding-top: 12px;
   }
 
-  svg {
-    width: 100%;
-    height: auto;
+  &__content {
+    flex: 1 1 auto;
+    padding: 10px 5px;
+    padding-right: 15px;
+    word-break: break-all;
+    overflow: hidden;
 
-    path:first-child {
-      fill: lighten($ui-base-color, 12%);
+    &__info {
+      overflow: hidden;
+      display: flex;
+      flex-direction: row-reverse;
+      justify-content: space-between;
     }
 
-    path:last-child {
-      fill: darken($ui-base-color, 14%);
+    &__relative-time {
+      font-size: 15px;
+      color: $darker-text-color;
+      padding-left: 15px;
     }
-  }
 
-  &__active {
-    color: $ui-highlight-color;
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    transform: translate(-50%, -50%);
-    background: lighten($ui-base-color, 12%);
-    border-radius: 50%;
-    padding: 0.35rem;
+    &__names {
+      color: $darker-text-color;
+      font-size: 15px;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      margin-bottom: 4px;
+      flex-basis: 170px;
+      flex-shrink: 1000;
+
+      a {
+        color: $primary-text-color;
+        text-decoration: none;
+
+        &:hover,
+        &:focus,
+        &:active {
+          text-decoration: underline;
+        }
+      }
+    }
+
+    .status__content {
+      margin: 0;
+    }
   }
 }
 
diff --git a/app/javascript/flavours/glitch/styles/components/modal.scss b/app/javascript/flavours/glitch/styles/components/modal.scss
index ec32c9114..4f3e5babf 100644
--- a/app/javascript/flavours/glitch/styles/components/modal.scss
+++ b/app/javascript/flavours/glitch/styles/components/modal.scss
@@ -405,7 +405,8 @@
 .confirmation-modal,
 .report-modal,
 .actions-modal,
-.mute-modal {
+.mute-modal,
+.block-modal {
   background: lighten($ui-secondary-color, 8%);
   color: $inverted-text-color;
   border-radius: 8px;
@@ -465,7 +466,8 @@
 .boost-modal__action-bar,
 .favourite-modal__action-bar,
 .confirmation-modal__action-bar,
-.mute-modal__action-bar {
+.mute-modal__action-bar,
+.block-modal__action-bar {
   display: flex;
   justify-content: space-between;
   background: $ui-secondary-color;
@@ -495,11 +497,13 @@
   font-size: 14px;
 }
 
-.mute-modal {
+.mute-modal,
+.block-modal {
   line-height: 24px;
 }
 
-.mute-modal .react-toggle {
+.mute-modal .react-toggle,
+.block-modal .react-toggle {
   vertical-align: middle;
 }
 
@@ -712,27 +716,29 @@
 }
 
 .confirmation-modal__action-bar,
-.mute-modal__action-bar {
-  .confirmation-modal__secondary-button,
-  .confirmation-modal__cancel-button,
-  .mute-modal__cancel-button {
-    background-color: transparent;
-    color: $lighter-text-color;
-    font-size: 14px;
-    font-weight: 500;
-
-    &:hover,
-    &:focus,
-    &:active {
-      color: darken($lighter-text-color, 4%);
-    }
-  }
-
+.mute-modal__action-bar,
+.block-modal__action-bar {
   .confirmation-modal__secondary-button {
     flex-shrink: 1;
   }
 }
 
+.confirmation-modal__secondary-button,
+.confirmation-modal__cancel-button,
+.mute-modal__cancel-button,
+.block-modal__cancel-button {
+  background-color: transparent;
+  color: $lighter-text-color;
+  font-size: 14px;
+  font-weight: 500;
+
+  &:hover,
+  &:focus,
+  &:active {
+    color: darken($lighter-text-color, 4%);
+  }
+}
+
 .confirmation-modal__do_not_ask_again {
   padding-left: 20px;
   padding-right: 20px;
@@ -747,10 +753,10 @@
 
 .confirmation-modal__container,
 .mute-modal__container,
+.block-modal__container,
 .report-modal__target {
   padding: 30px;
   font-size: 16px;
-  text-align: center;
 
   strong {
     font-weight: 500;
@@ -763,6 +769,31 @@
   }
 }
 
+.confirmation-modal__container,
+.report-modal__target {
+  text-align: center;
+}
+
+.block-modal,
+.mute-modal {
+  &__explanation {
+    margin-top: 20px;
+  }
+
+  .setting-toggle {
+    margin-top: 20px;
+    margin-bottom: 24px;
+    display: flex;
+    align-items: center;
+
+    &__label {
+      color: $inverted-text-color;
+      margin: 0;
+      margin-left: 8px;
+    }
+  }
+}
+
 .report-modal__target {
   padding: 15px;
 
diff --git a/app/javascript/flavours/glitch/styles/components/search.scss b/app/javascript/flavours/glitch/styles/components/search.scss
index c3ea47eb0..30d69d05c 100644
--- a/app/javascript/flavours/glitch/styles/components/search.scss
+++ b/app/javascript/flavours/glitch/styles/components/search.scss
@@ -10,6 +10,28 @@
   padding-right: 30px;
   line-height: 18px;
   font-size: 16px;
+
+  &::placeholder {
+    color: lighten($darker-text-color, 4%);
+  }
+
+  &::-moz-focus-inner {
+    border: 0;
+  }
+
+  &::-moz-focus-inner,
+  &:focus,
+  &:active {
+    outline: 0 !important;
+  }
+
+  &:focus {
+    background: lighten($ui-base-color, 4%);
+  }
+
+  @media screen and (max-width: 600px) {
+    font-size: 16px;
+  }
 }
 
 .search__icon {
diff --git a/app/javascript/flavours/glitch/styles/components/status.scss b/app/javascript/flavours/glitch/styles/components/status.scss
index 24ab71969..ae89ac0a8 100644
--- a/app/javascript/flavours/glitch/styles/components/status.scss
+++ b/app/javascript/flavours/glitch/styles/components/status.scss
@@ -673,6 +673,7 @@ a.status__display-name,
 }
 
 .muted {
+  .status__content,
   .status__content p,
   .status__content a,
   .status__content__text {
diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss
index 17455ca58..6a48ff354 100644
--- a/app/javascript/flavours/glitch/styles/containers.scss
+++ b/app/javascript/flavours/glitch/styles/containers.scss
@@ -143,6 +143,63 @@
     grid-row: 3;
   }
 
+  @media screen and (max-width: $no-gap-breakpoint) {
+    grid-gap: 0;
+    grid-template-columns: minmax(0, 100%);
+
+    .column-0 {
+      grid-column: 1;
+    }
+
+    .column-1 {
+      grid-column: 1;
+      grid-row: 3;
+    }
+
+    .column-2 {
+      grid-column: 1;
+      grid-row: 2;
+    }
+
+    .column-3 {
+      grid-column: 1;
+      grid-row: 4;
+    }
+  }
+}
+
+.grid-4 {
+  display: grid;
+  grid-gap: 10px;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  grid-auto-columns: 25%;
+  grid-auto-rows: max-content;
+
+  .column-0 {
+    grid-column: 1 / 5;
+    grid-row: 1;
+  }
+
+  .column-1 {
+    grid-column: 1 / 4;
+    grid-row: 2;
+  }
+
+  .column-2 {
+    grid-column: 4;
+    grid-row: 2;
+  }
+
+  .column-3 {
+    grid-column: 2 / 5;
+    grid-row: 3;
+  }
+
+  .column-4 {
+    grid-column: 1;
+    grid-row: 3;
+  }
+
   .landing-page__call-to-action {
     min-height: 100%;
   }
@@ -192,6 +249,11 @@
 
     .column-3 {
       grid-column: 1;
+      grid-row: 5;
+    }
+
+    .column-4 {
+      grid-column: 1;
       grid-row: 4;
     }
   }
diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss
index dae29a003..747c5309d 100644
--- a/app/javascript/flavours/glitch/styles/forms.scss
+++ b/app/javascript/flavours/glitch/styles/forms.scss
@@ -245,6 +245,10 @@ code {
       &-6 {
         max-width: 50%;
       }
+
+      .actions {
+        margin-top: 27px;
+      }
     }
 
     .fields-group:last-child,
@@ -300,6 +304,13 @@ code {
     }
   }
 
+  .input.static .label_input__wrapper {
+    font-size: 16px;
+    padding: 10px;
+    border: 1px solid $dark-text-color;
+    border-radius: 4px;
+  }
+
   input[type=text],
   input[type=number],
   input[type=email],
@@ -318,6 +329,10 @@ code {
     border-radius: 4px;
     padding: 10px;
 
+    &::placeholder {
+      color: lighten($darker-text-color, 4%);
+    }
+
     &:invalid {
       box-shadow: none;
     }
diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss
index 4c2b76a21..5c7fa87da 100644
--- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss
+++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss
@@ -226,6 +226,7 @@
 .boost-modal,
 .confirmation-modal,
 .mute-modal,
+.block-modal,
 .report-modal,
 .embed-modal,
 .error-modal,
@@ -236,6 +237,7 @@
 .boost-modal__action-bar,
 .confirmation-modal__action-bar,
 .mute-modal__action-bar,
+.block-modal__action-bar,
 .onboarding-modal__paginator,
 .error-modal__footer {
   background: darken($ui-base-color, 6%);
diff --git a/app/javascript/flavours/glitch/styles/polls.scss b/app/javascript/flavours/glitch/styles/polls.scss
index 06f60408d..95d8e510c 100644
--- a/app/javascript/flavours/glitch/styles/polls.scss
+++ b/app/javascript/flavours/glitch/styles/polls.scss
@@ -102,13 +102,19 @@
 
   &__number {
     display: inline-block;
-    width: 36px;
+    width: 52px;
     font-weight: 700;
     padding: 0 10px;
+    padding-left: 8px;
     text-align: right;
     margin-top: auto;
     margin-bottom: auto;
-    flex: 0 0 36px;
+    flex: 0 0 52px;
+  }
+
+  &__vote__mark {
+    float: left;
+    line-height: 18px;
   }
 
   &__footer {
diff --git a/app/javascript/flavours/glitch/styles/tables.scss b/app/javascript/flavours/glitch/styles/tables.scss
index 669f72787..b84f6a708 100644
--- a/app/javascript/flavours/glitch/styles/tables.scss
+++ b/app/javascript/flavours/glitch/styles/tables.scss
@@ -288,70 +288,3 @@ a.table-action-link {
     }
   }
 }
-
-.blocks-table {
-  width: 100%;
-  max-width: 100%;
-  border-spacing: 0;
-  border-collapse: collapse;
-  table-layout: fixed;
-  border: 1px solid darken($ui-base-color, 8%);
-
-  thead {
-    border: 1px solid darken($ui-base-color, 8%);
-    background: darken($ui-base-color, 4%);
-    font-weight: 500;
-
-    th.severity-column {
-      width: 120px;
-    }
-
-    th.button-column {
-      width: 23px;
-    }
-  }
-
-  tbody > tr {
-    border: 1px solid darken($ui-base-color, 8%);
-    border-bottom: 0;
-    background: darken($ui-base-color, 4%);
-
-    &:hover {
-      background: darken($ui-base-color, 2%);
-    }
-
-    &.even {
-      background: $ui-base-color;
-
-      &:hover {
-        background: lighten($ui-base-color, 2%);
-      }
-    }
-
-    &.rationale {
-      background: lighten($ui-base-color, 4%);
-      border-top: 0;
-
-      &:hover {
-        background: lighten($ui-base-color, 6%);
-      }
-
-      &.hidden {
-        display: none;
-      }
-    }
-
-    td:first-child {
-      overflow: hidden;
-      text-overflow: ellipsis;
-    }
-  }
-
-  th,
-  td {
-    padding: 8px;
-    line-height: 18px;
-    vertical-align: top;
-    text-align: left;
-  }
-}
diff --git a/app/javascript/flavours/glitch/styles/widgets.scss b/app/javascript/flavours/glitch/styles/widgets.scss
index 9e9c6eb58..a6f7fc0be 100644
--- a/app/javascript/flavours/glitch/styles/widgets.scss
+++ b/app/javascript/flavours/glitch/styles/widgets.scss
@@ -128,41 +128,43 @@
   margin-bottom: 10px;
 }
 
-.contact-widget,
-.landing-page__information.contact-widget {
-  box-sizing: border-box;
-  padding: 20px;
-  min-height: 100%;
-  border-radius: 4px;
-  background: $ui-base-color;
-  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
-}
-
 .contact-widget {
+  min-height: 100%;
   font-size: 15px;
   color: $darker-text-color;
   line-height: 20px;
   word-wrap: break-word;
   font-weight: 400;
+  padding: 0;
 
-  strong {
-    font-weight: 500;
+  h4 {
+    padding: 10px;
+    text-transform: uppercase;
+    font-weight: 700;
+    font-size: 13px;
+    color: $darker-text-color;
   }
 
-  p {
-    margin-bottom: 10px;
-
-    &:last-child {
-      margin-bottom: 0;
-    }
+  .account {
+    border-bottom: 0;
+    padding: 10px 0;
+    padding-top: 5px;
   }
 
-  &__mail {
-    margin-top: 10px;
+  & > a {
+    display: inline-block;
+    padding: 10px;
+    padding-top: 0;
+    color: $darker-text-color;
+    text-decoration: none;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
 
-    a {
-      color: $primary-text-color;
-      text-decoration: none;
+    &:hover,
+    &:focus,
+    &:active {
+      text-decoration: underline;
     }
   }
 }
@@ -557,3 +559,38 @@ $fluid-breakpoint: $maximum-width + 20px;
     }
   }
 }
+
+.table-of-contents {
+  background: darken($ui-base-color, 4%);
+  min-height: 100%;
+  font-size: 14px;
+  border-radius: 4px;
+
+  li a {
+    display: block;
+    font-weight: 500;
+    padding: 15px;
+    overflow: hidden;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    text-decoration: none;
+    color: $primary-text-color;
+    border-bottom: 1px solid lighten($ui-base-color, 4%);
+
+    &:hover,
+    &:focus,
+    &:active {
+      text-decoration: underline;
+    }
+  }
+
+  li:last-child a {
+    border-bottom: 0;
+  }
+
+  li ul {
+    padding-left: 20px;
+    border-bottom: 1px solid lighten($ui-base-color, 4%);
+  }
+}
diff --git a/app/javascript/flavours/glitch/theme.yml b/app/javascript/flavours/glitch/theme.yml
index 06e26ade2..0fd627f19 100644
--- a/app/javascript/flavours/glitch/theme.yml
+++ b/app/javascript/flavours/glitch/theme.yml
@@ -18,7 +18,7 @@ pack:
   mailer:
   modal:
   public: packs/public.js
-  settings:
+  settings: packs/settings.js
   share: packs/share.js
 
 #  (OPTIONAL) The directory which contains localization files for
diff --git a/app/javascript/flavours/glitch/util/async-components.js b/app/javascript/flavours/glitch/util/async-components.js
index 6c0acdb27..26255bbb7 100644
--- a/app/javascript/flavours/glitch/util/async-components.js
+++ b/app/javascript/flavours/glitch/util/async-components.js
@@ -122,6 +122,10 @@ export function MuteModal () {
   return import(/* webpackChunkName: "flavours/glitch/async/mute_modal" */'flavours/glitch/features/ui/components/mute_modal');
 }
 
+export function BlockModal () {
+  return import(/* webpackChunkName: "flavours/glitch/async/block_modal" */'flavours/glitch/features/ui/components/block_modal');
+}
+
 export function ReportModal () {
   return import(/* webpackChunkName: "flavours/glitch/async/report_modal" */'flavours/glitch/features/ui/components/report_modal');
 }
diff --git a/app/javascript/flavours/glitch/util/emoji/index.js b/app/javascript/flavours/glitch/util/emoji/index.js
index b2d13cc95..e1a244127 100644
--- a/app/javascript/flavours/glitch/util/emoji/index.js
+++ b/app/javascript/flavours/glitch/util/emoji/index.js
@@ -100,4 +100,4 @@ export const buildCustomEmojis = (customEmojis) => {
   return emojis;
 };
 
-export const categoriesFromEmojis = customEmojis => customEmojis.reduce((set, emoji) => set.add(emoji.get('category') ? `custom-${emoji.get('category')}` : 'custom'), new Set());
+export const categoriesFromEmojis = customEmojis => customEmojis.reduce((set, emoji) => set.add(emoji.get('category') ? `custom-${emoji.get('category')}` : 'custom'), new Set(['custom']));
diff --git a/app/javascript/mastodon/actions/blocks.js b/app/javascript/mastodon/actions/blocks.js
index 7000f5a71..fd9881302 100644
--- a/app/javascript/mastodon/actions/blocks.js
+++ b/app/javascript/mastodon/actions/blocks.js
@@ -1,6 +1,7 @@
 import api, { getLinks } from '../api';
 import { fetchRelationships } from './accounts';
 import { importFetchedAccounts } from './importer';
+import { openModal } from './modal';
 
 export const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST';
 export const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS';
@@ -10,6 +11,8 @@ export const BLOCKS_EXPAND_REQUEST = 'BLOCKS_EXPAND_REQUEST';
 export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS';
 export const BLOCKS_EXPAND_FAIL    = 'BLOCKS_EXPAND_FAIL';
 
+export const BLOCKS_INIT_MODAL = 'BLOCKS_INIT_MODAL';
+
 export function fetchBlocks() {
   return (dispatch, getState) => {
     dispatch(fetchBlocksRequest());
@@ -83,3 +86,14 @@ export function expandBlocksFail(error) {
     error,
   };
 };
+
+export function initBlockModal(account) {
+  return dispatch => {
+    dispatch({
+      type: BLOCKS_INIT_MODAL,
+      account,
+    });
+
+    dispatch(openModal('BLOCK'));
+  };
+}
diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js
index 061a36bb8..8e7906c73 100644
--- a/app/javascript/mastodon/actions/compose.js
+++ b/app/javascript/mastodon/actions/compose.js
@@ -234,7 +234,7 @@ export function uploadCompose(files) {
             progress[i] = loaded;
             dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
           },
-        }).then(({ data }) => dispatch(uploadComposeSuccess(data)));
+        }).then(({ data }) => dispatch(uploadComposeSuccess(data, f)));
       }).catch(error => dispatch(uploadComposeFail(error)));
     };
   };
@@ -289,10 +289,11 @@ export function uploadComposeProgress(loaded, total) {
   };
 };
 
-export function uploadComposeSuccess(media) {
+export function uploadComposeSuccess(media, file) {
   return {
     type: COMPOSE_UPLOAD_SUCCESS,
     media: media,
+    file: file,
     skipLoading: true,
   };
 };
@@ -368,6 +369,7 @@ const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => {
       q: token.slice(1),
       resolve: false,
       limit: 4,
+      exclude_unreviewed: true,
     },
   }).then(({ data }) => {
     dispatch(readyComposeSuggestionsTags(token, data.hashtags));
diff --git a/app/javascript/mastodon/actions/conversations.js b/app/javascript/mastodon/actions/conversations.js
index c6e062ef7..4ef654b1f 100644
--- a/app/javascript/mastodon/actions/conversations.js
+++ b/app/javascript/mastodon/actions/conversations.js
@@ -15,6 +15,10 @@ export const CONVERSATIONS_UPDATE        = 'CONVERSATIONS_UPDATE';
 
 export const CONVERSATIONS_READ = 'CONVERSATIONS_READ';
 
+export const CONVERSATIONS_DELETE_REQUEST = 'CONVERSATIONS_DELETE_REQUEST';
+export const CONVERSATIONS_DELETE_SUCCESS = 'CONVERSATIONS_DELETE_SUCCESS';
+export const CONVERSATIONS_DELETE_FAIL    = 'CONVERSATIONS_DELETE_FAIL';
+
 export const mountConversations = () => ({
   type: CONVERSATIONS_MOUNT,
 });
@@ -82,3 +86,27 @@ export const updateConversations = conversation => dispatch => {
     conversation,
   });
 };
+
+export const deleteConversation = conversationId => (dispatch, getState) => {
+  dispatch(deleteConversationRequest(conversationId));
+
+  api(getState).delete(`/api/v1/conversations/${conversationId}`)
+    .then(() => dispatch(deleteConversationSuccess(conversationId)))
+    .catch(error => dispatch(deleteConversationFail(conversationId, error)));
+};
+
+export const deleteConversationRequest = id => ({
+  type: CONVERSATIONS_DELETE_REQUEST,
+  id,
+});
+
+export const deleteConversationSuccess = id => ({
+  type: CONVERSATIONS_DELETE_SUCCESS,
+  id,
+});
+
+export const deleteConversationFail = (id, error) => ({
+  type: CONVERSATIONS_DELETE_FAIL,
+  id,
+  error,
+});
diff --git a/app/javascript/mastodon/actions/importer/normalizer.js b/app/javascript/mastodon/actions/importer/normalizer.js
index 5e7e78e69..f7108fdb9 100644
--- a/app/javascript/mastodon/actions/importer/normalizer.js
+++ b/app/javascript/mastodon/actions/importer/normalizer.js
@@ -73,8 +73,9 @@ export function normalizePoll(poll) {
 
   const emojiMap = makeEmojiMap(normalPoll);
 
-  normalPoll.options = poll.options.map(option => ({
+  normalPoll.options = poll.options.map((option, index) => ({
     ...option,
+    voted: poll.own_votes && poll.own_votes.includes(index),
     title_emojified: emojify(escapeTextContentForBrowser(option.title), emojiMap),
   }));
 
diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js
index ea76255e3..58803d1ae 100644
--- a/app/javascript/mastodon/actions/notifications.js
+++ b/app/javascript/mastodon/actions/notifications.js
@@ -28,6 +28,9 @@ export const NOTIFICATIONS_CLEAR        = 'NOTIFICATIONS_CLEAR';
 export const NOTIFICATIONS_SCROLL_TOP   = 'NOTIFICATIONS_SCROLL_TOP';
 export const NOTIFICATIONS_LOAD_PENDING = 'NOTIFICATIONS_LOAD_PENDING';
 
+export const NOTIFICATIONS_MOUNT   = 'NOTIFICATIONS_MOUNT';
+export const NOTIFICATIONS_UNMOUNT = 'NOTIFICATIONS_UNMOUNT';
+
 defineMessages({
   mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
   group: { id: 'notifications.group', defaultMessage: '{count} notifications' },
@@ -215,3 +218,11 @@ export function setFilter (filterType) {
     dispatch(saveSettings());
   };
 };
+
+export const mountNotifications = () => ({
+  type: NOTIFICATIONS_MOUNT,
+});
+
+export const unmountNotifications = () => ({
+  type: NOTIFICATIONS_UNMOUNT,
+});
diff --git a/app/javascript/mastodon/components/avatar_composite.js b/app/javascript/mastodon/components/avatar_composite.js
index 4a9a73c51..5d5b89749 100644
--- a/app/javascript/mastodon/components/avatar_composite.js
+++ b/app/javascript/mastodon/components/avatar_composite.js
@@ -35,35 +35,35 @@ export default class AvatarComposite extends React.PureComponent {
 
     if (size === 2) {
       if (index === 0) {
-        right = '2px';
+        right = '1px';
       } else {
-        left = '2px';
+        left = '1px';
       }
     } else if (size === 3) {
       if (index === 0) {
-        right = '2px';
+        right = '1px';
       } else if (index > 0) {
-        left = '2px';
+        left = '1px';
       }
 
       if (index === 1) {
-        bottom = '2px';
+        bottom = '1px';
       } else if (index > 1) {
-        top = '2px';
+        top = '1px';
       }
     } else if (size === 4) {
       if (index === 0 || index === 2) {
-        right = '2px';
+        right = '1px';
       }
 
       if (index === 1 || index === 3) {
-        left = '2px';
+        left = '1px';
       }
 
       if (index < 2) {
-        bottom = '2px';
+        bottom = '1px';
       } else {
-        top = '2px';
+        top = '1px';
       }
     }
 
@@ -88,7 +88,13 @@ export default class AvatarComposite extends React.PureComponent {
 
     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))}
+        {accounts.take(4).map((account, i) => this.renderItem(account, Math.min(accounts.size, 4), i))}
+
+        {accounts.size > 4 && (
+          <span className='account__avatar-composite__label'>
+            +{accounts.size - 4}
+          </span>
+        )}
       </div>
     );
   }
diff --git a/app/javascript/mastodon/components/column_header.js b/app/javascript/mastodon/components/column_header.js
index 8a26742b5..0038995c8 100644
--- a/app/javascript/mastodon/components/column_header.js
+++ b/app/javascript/mastodon/components/column_header.js
@@ -120,7 +120,7 @@ class ColumnHeader extends React.PureComponent {
           <button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='text-btn column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' /></button>
         </div>
       );
-    } else if (multiColumn) {
+    } else if (multiColumn && this.props.onPin) {
       pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
     }
 
@@ -142,7 +142,7 @@ class ColumnHeader extends React.PureComponent {
       collapsedContent.push(pinButton);
     }
 
-    if (children || multiColumn) {
+    if (children || (multiColumn && this.props.onPin)) {
       collapseButton = <button className={collapsibleButtonClassName} title={formatMessage(collapsed ? messages.show : messages.hide)} aria-label={formatMessage(collapsed ? messages.show : messages.hide)} aria-pressed={collapsed ? 'false' : 'true'} onClick={this.handleToggleClick}><Icon id='sliders' /></button>;
     }
 
diff --git a/app/javascript/mastodon/components/poll.js b/app/javascript/mastodon/components/poll.js
index 373f710d3..cdbcf8f70 100644
--- a/app/javascript/mastodon/components/poll.js
+++ b/app/javascript/mastodon/components/poll.js
@@ -10,9 +10,11 @@ import spring from 'react-motion/lib/spring';
 import escapeTextContentForBrowser from 'escape-html';
 import emojify from 'mastodon/features/emoji/emoji';
 import RelativeTimestamp from './relative_timestamp';
+import Icon from 'mastodon/components/icon';
 
 const messages = defineMessages({
   closed: { id: 'poll.closed', defaultMessage: 'Closed' },
+  voted: { id: 'poll.voted', defaultMessage: 'You voted for this answer', description: 'Tooltip of the "voted" checkmark in polls' },
 });
 
 const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
@@ -99,10 +101,12 @@ class Poll extends ImmutablePureComponent {
   };
 
   renderOption (option, optionIndex, showResults) {
-    const { poll, disabled } = this.props;
-    const percent            = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100;
-    const leading            = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count'));
-    const active             = !!this.state.selected[`${optionIndex}`];
+    const { poll, disabled, intl } = this.props;
+    const pollVotesCount  = poll.get('voters_count') || poll.get('votes_count');
+    const percent         = pollVotesCount === 0 ? 0 : (option.get('votes_count') / pollVotesCount) * 100;
+    const leading         = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') >= other.get('votes_count'));
+    const active          = !!this.state.selected[`${optionIndex}`];
+    const voted           = option.get('voted') || (poll.get('own_votes') && poll.get('own_votes').includes(optionIndex));
 
     let titleEmojified = option.get('title_emojified');
     if (!titleEmojified) {
@@ -131,7 +135,10 @@ class Poll extends ImmutablePureComponent {
           />
 
           {!showResults && <span className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} />}
-          {showResults && <span className='poll__number'>{Math.round(percent)}%</span>}
+          {showResults && <span className='poll__number'>
+            {!!voted && <Icon id='check' className='poll__vote__mark' title={intl.formatMessage(messages.voted)} />}
+            {Math.round(percent)}%
+          </span>}
 
           <span dangerouslySetInnerHTML={{ __html: titleEmojified }} />
         </label>
@@ -151,6 +158,14 @@ class Poll extends ImmutablePureComponent {
     const showResults   = poll.get('voted') || expired;
     const disabled      = this.props.disabled || Object.entries(this.state.selected).every(item => !item);
 
+    let votesCount = null;
+
+    if (poll.get('voters_count') !== null && poll.get('voters_count') !== undefined) {
+      votesCount = <FormattedMessage id='poll.total_people' defaultMessage='{count, plural, one {# person} other {# people}}' values={{ count: poll.get('voters_count') }} />;
+    } else {
+      votesCount = <FormattedMessage id='poll.total_votes' defaultMessage='{count, plural, one {# vote} other {# votes}}' values={{ count: poll.get('votes_count') }} />;
+    }
+
     return (
       <div className='poll'>
         <ul>
@@ -160,7 +175,7 @@ class Poll extends ImmutablePureComponent {
         <div className='poll__footer'>
           {!showResults && <button className='button button-secondary' disabled={disabled} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
           {showResults && !this.props.disabled && <span><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </span>}
-          <FormattedMessage id='poll.total_votes' defaultMessage='{count, plural, one {# vote} other {# votes}}' values={{ count: poll.get('votes_count') }} />
+          {votesCount}
           {poll.get('expires_at') && <span> · {timeRemaining}</span>}
         </div>
       </div>
diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js
index 253646ed0..421756803 100644
--- a/app/javascript/mastodon/components/scrollable_list.js
+++ b/app/javascript/mastodon/components/scrollable_list.js
@@ -199,6 +199,7 @@ export default class ScrollableList extends PureComponent {
     this.clearMouseIdleTimer();
     this.detachScrollListener();
     this.detachIntersectionObserver();
+
     detachFullscreenListener(this.onFullScreenChange);
   }
 
diff --git a/app/javascript/mastodon/containers/media_container.js b/app/javascript/mastodon/containers/media_container.js
index db340032a..ba55ecbc7 100644
--- a/app/javascript/mastodon/containers/media_container.js
+++ b/app/javascript/mastodon/containers/media_container.js
@@ -2,17 +2,17 @@ import React, { PureComponent, Fragment } from 'react';
 import ReactDOM from 'react-dom';
 import PropTypes from 'prop-types';
 import { IntlProvider, addLocaleData } from 'react-intl';
-import { getLocale } from '../locales';
-import MediaGallery from '../components/media_gallery';
-import Video from '../features/video';
-import Card from '../features/status/components/card';
+import { List as ImmutableList, fromJS } from 'immutable';
+import { getLocale } from 'mastodon/locales';
+import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
+import MediaGallery from 'mastodon/components/media_gallery';
 import Poll from 'mastodon/components/poll';
 import Hashtag from 'mastodon/components/hashtag';
+import ModalRoot from 'mastodon/components/modal_root';
+import MediaModal from 'mastodon/features/ui/components/media_modal';
+import Video from 'mastodon/features/video';
+import Card from 'mastodon/features/status/components/card';
 import Audio from 'mastodon/features/audio';
-import ModalRoot from '../components/modal_root';
-import { getScrollbarWidth } from '../features/ui/components/modal_root';
-import MediaModal from '../features/ui/components/media_modal';
-import { List as ImmutableList, fromJS } from 'immutable';
 
 const { localeData, messages } = getLocale();
 addLocaleData(localeData);
diff --git a/app/javascript/mastodon/containers/status_container.js b/app/javascript/mastodon/containers/status_container.js
index fa58589a6..fb22676e0 100644
--- a/app/javascript/mastodon/containers/status_container.js
+++ b/app/javascript/mastodon/containers/status_container.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import Status from '../components/status';
 import { makeGetStatus } from '../selectors';
@@ -15,7 +14,6 @@ import {
   pin,
   unpin,
 } from '../actions/interactions';
-import { blockAccount } from '../actions/accounts';
 import {
   muteStatus,
   unmuteStatus,
@@ -24,9 +22,10 @@ import {
   revealStatus,
 } from '../actions/statuses';
 import { initMuteModal } from '../actions/mutes';
+import { initBlockModal } from '../actions/blocks';
 import { initReport } from '../actions/reports';
 import { openModal } from '../actions/modal';
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { defineMessages, injectIntl } from 'react-intl';
 import { boostModal, deleteModal } from '../initial_state';
 import { showAlertForError } from '../actions/alerts';
 
@@ -35,10 +34,8 @@ const messages = defineMessages({
   deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
   redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
   redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: '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.' },
-  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
   replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
   replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
-  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
 });
 
 const makeMapStateToProps = () => {
@@ -56,6 +53,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
   onReply (status, router) {
     dispatch((_, getState) => {
       let state = getState();
+
       if (state.getIn(['compose', 'text']).trim().length !== 0) {
         dispatch(openModal('CONFIRM', {
           message: intl.formatMessage(messages.replyMessage),
@@ -137,16 +135,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
 
   onBlock (status) {
     const account = status.get('account');
-    dispatch(openModal('CONFIRM', {
-      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
-      confirm: intl.formatMessage(messages.blockConfirm),
-      onConfirm: () => dispatch(blockAccount(account.get('id'))),
-      secondary: intl.formatMessage(messages.blockAndReport),
-      onSecondary: () => {
-        dispatch(blockAccount(account.get('id')));
-        dispatch(initReport(account, status));
-      },
-    }));
+    dispatch(initBlockModal(account));
   },
 
   onReport (status) {
diff --git a/app/javascript/mastodon/features/account_timeline/containers/header_container.js b/app/javascript/mastodon/features/account_timeline/containers/header_container.js
index 4d4ae6e82..8728b4806 100644
--- a/app/javascript/mastodon/features/account_timeline/containers/header_container.js
+++ b/app/javascript/mastodon/features/account_timeline/containers/header_container.js
@@ -5,7 +5,6 @@ import Header from '../components/header';
 import {
   followAccount,
   unfollowAccount,
-  blockAccount,
   unblockAccount,
   unmuteAccount,
   pinAccount,
@@ -16,6 +15,7 @@ import {
   directCompose,
 } from '../../../actions/compose';
 import { initMuteModal } from '../../../actions/mutes';
+import { initBlockModal } from '../../../actions/blocks';
 import { initReport } from '../../../actions/reports';
 import { openModal } from '../../../actions/modal';
 import { blockDomain, unblockDomain } from '../../../actions/domain_blocks';
@@ -25,9 +25,7 @@ import { List as ImmutableList } from 'immutable';
 
 const messages = defineMessages({
   unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
-  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
   blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
-  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
 });
 
 const makeMapStateToProps = () => {
@@ -64,16 +62,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
     if (account.getIn(['relationship', 'blocking'])) {
       dispatch(unblockAccount(account.get('id')));
     } else {
-      dispatch(openModal('CONFIRM', {
-        message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
-        confirm: intl.formatMessage(messages.blockConfirm),
-        onConfirm: () => dispatch(blockAccount(account.get('id'))),
-        secondary: intl.formatMessage(messages.blockAndReport),
-        onSecondary: () => {
-          dispatch(blockAccount(account.get('id')));
-          dispatch(initReport(account));
-        },
-      }));
+      dispatch(initBlockModal(account));
     }
   },
 
diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.js b/app/javascript/mastodon/features/direct_timeline/components/conversation.js
index ffcd6d281..cc3faf0de 100644
--- a/app/javascript/mastodon/features/direct_timeline/components/conversation.js
+++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.js
@@ -2,9 +2,28 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
-import StatusContainer from '../../../containers/status_container';
+import StatusContent from 'mastodon/components/status_content';
+import AttachmentList from 'mastodon/components/attachment_list';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
+import AvatarComposite from 'mastodon/components/avatar_composite';
+import Permalink from 'mastodon/components/permalink';
+import IconButton from 'mastodon/components/icon_button';
+import RelativeTimestamp from 'mastodon/components/relative_timestamp';
+import { HotKeys } from 'react-hotkeys';
 
-export default class Conversation extends ImmutablePureComponent {
+const messages = defineMessages({
+  more: { id: 'status.more', defaultMessage: 'More' },
+  open: { id: 'conversation.open', defaultMessage: 'View conversation' },
+  reply: { id: 'status.reply', defaultMessage: 'Reply' },
+  markAsRead: { id: 'conversation.mark_as_read', defaultMessage: 'Mark as read' },
+  delete: { id: 'conversation.delete', defaultMessage: 'Delete conversation' },
+  muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
+  unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
+});
+
+export default @injectIntl
+class Conversation extends ImmutablePureComponent {
 
   static contextTypes = {
     router: PropTypes.object,
@@ -13,11 +32,12 @@ export default class Conversation extends ImmutablePureComponent {
   static propTypes = {
     conversationId: PropTypes.string.isRequired,
     accounts: ImmutablePropTypes.list.isRequired,
-    lastStatusId: PropTypes.string,
+    lastStatus: ImmutablePropTypes.map,
     unread:PropTypes.bool.isRequired,
     onMoveUp: PropTypes.func,
     onMoveDown: PropTypes.func,
     markRead: PropTypes.func.isRequired,
+    intl: PropTypes.object.isRequired,
   };
 
   handleClick = () => {
@@ -25,13 +45,25 @@ export default class Conversation extends ImmutablePureComponent {
       return;
     }
 
-    const { lastStatusId, unread, markRead } = this.props;
+    const { lastStatus, unread, markRead } = this.props;
 
     if (unread) {
       markRead();
     }
 
-    this.context.router.history.push(`/statuses/${lastStatusId}`);
+    this.context.router.history.push(`/statuses/${lastStatus.get('id')}`);
+  }
+
+  handleMarkAsRead = () => {
+    this.props.markRead();
+  }
+
+  handleReply = () => {
+    this.props.reply(this.props.lastStatus, this.context.router.history);
+  }
+
+  handleDelete = () => {
+    this.props.delete();
   }
 
   handleHotkeyMoveUp = () => {
@@ -42,22 +74,88 @@ export default class Conversation extends ImmutablePureComponent {
     this.props.onMoveDown(this.props.conversationId);
   }
 
+  handleConversationMute = () => {
+    this.props.onMute(this.props.lastStatus);
+  }
+
+  handleShowMore = () => {
+    this.props.onToggleHidden(this.props.lastStatus);
+  }
+
   render () {
-    const { accounts, lastStatusId, unread } = this.props;
+    const { accounts, lastStatus, unread, intl } = this.props;
 
-    if (lastStatusId === null) {
+    if (lastStatus === null) {
       return null;
     }
 
+    const menu = [
+      { text: intl.formatMessage(messages.open), action: this.handleClick },
+      null,
+    ];
+
+    menu.push({ text: intl.formatMessage(lastStatus.get('muted') ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMute });
+
+    if (unread) {
+      menu.push({ text: intl.formatMessage(messages.markAsRead), action: this.handleMarkAsRead });
+      menu.push(null);
+    }
+
+    menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDelete });
+
+    const names = accounts.map(a => <Permalink to={`/accounts/${a.get('id')}`} href={a.get('url')} key={a.get('id')} title={a.get('acct')}><bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }} /></bdi></Permalink>).reduce((prev, cur) => [prev, ', ', cur]);
+
+    const handlers = {
+      reply: this.handleReply,
+      open: this.handleClick,
+      moveUp: this.handleHotkeyMoveUp,
+      moveDown: this.handleHotkeyMoveDown,
+      toggleHidden: this.handleShowMore,
+    };
+
     return (
-      <StatusContainer
-        id={lastStatusId}
-        unread={unread}
-        otherAccounts={accounts}
-        onMoveUp={this.handleHotkeyMoveUp}
-        onMoveDown={this.handleHotkeyMoveDown}
-        onClick={this.handleClick}
-      />
+      <HotKeys handlers={handlers}>
+        <div className='conversation focusable muted' tabIndex='0'>
+          <div className='conversation__avatar'>
+            <AvatarComposite accounts={accounts} size={48} />
+          </div>
+
+          <div className='conversation__content'>
+            <div className='conversation__content__info'>
+              <div className='conversation__content__relative-time'>
+                <RelativeTimestamp timestamp={lastStatus.get('created_at')} />
+              </div>
+
+              <div className='conversation__content__names'>
+                <FormattedMessage id='conversation.with' defaultMessage='With {names}' values={{ names: <span>{names}</span> }} />
+              </div>
+            </div>
+
+            <StatusContent
+              status={lastStatus}
+              onClick={this.handleClick}
+              expanded={!lastStatus.get('hidden')}
+              onExpandedToggle={this.handleShowMore}
+              collapsable
+            />
+
+            {lastStatus.get('media_attachments').size > 0 && (
+              <AttachmentList
+                compact
+                media={lastStatus.get('media_attachments')}
+              />
+            )}
+
+            <div className='status__action-bar'>
+              <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.reply)} icon='reply' onClick={this.handleReply} />
+
+              <div className='status__action-bar-dropdown'>
+                <DropdownMenuContainer status={lastStatus} items={menu} icon='ellipsis-h' size={18} direction='right' title={intl.formatMessage(messages.more)} />
+              </div>
+            </div>
+          </div>
+        </div>
+      </HotKeys>
     );
   }
 
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 bd6f6bfb0..94cef81a7 100644
--- a/app/javascript/mastodon/features/direct_timeline/containers/conversation_container.js
+++ b/app/javascript/mastodon/features/direct_timeline/containers/conversation_container.js
@@ -1,19 +1,74 @@
 import { connect } from 'react-redux';
 import Conversation from '../components/conversation';
-import { markConversationRead } from '../../../actions/conversations';
+import { markConversationRead, deleteConversation } from 'mastodon/actions/conversations';
+import { makeGetStatus } from 'mastodon/selectors';
+import { replyCompose } from 'mastodon/actions/compose';
+import { openModal } from 'mastodon/actions/modal';
+import { muteStatus, unmuteStatus, hideStatus, revealStatus } from 'mastodon/actions/statuses';
+import { defineMessages, injectIntl } from 'react-intl';
 
-const mapStateToProps = (state, { conversationId }) => {
-  const conversation = state.getIn(['conversations', 'items']).find(x => x.get('id') === conversationId);
+const messages = defineMessages({
+  replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
+  replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
+});
+
+const mapStateToProps = () => {
+  const getStatus = makeGetStatus();
+
+  return (state, { conversationId }) => {
+    const conversation = state.getIn(['conversations', 'items']).find(x => x.get('id') === conversationId);
+    const lastStatusId = conversation.get('last_status', null);
 
-  return {
-    accounts: conversation.get('accounts').map(accountId => state.getIn(['accounts', accountId], null)),
-    unread: conversation.get('unread'),
-    lastStatusId: conversation.get('last_status', null),
+    return {
+      accounts: conversation.get('accounts').map(accountId => state.getIn(['accounts', accountId], null)),
+      unread: conversation.get('unread'),
+      lastStatus: lastStatusId && getStatus(state, { id: lastStatusId }),
+    };
   };
 };
 
-const mapDispatchToProps = (dispatch, { conversationId }) => ({
-  markRead: () => dispatch(markConversationRead(conversationId)),
+const mapDispatchToProps = (dispatch, { intl, conversationId }) => ({
+
+  markRead () {
+    dispatch(markConversationRead(conversationId));
+  },
+
+  reply (status, router) {
+    dispatch((_, getState) => {
+      let state = getState();
+
+      if (state.getIn(['compose', 'text']).trim().length !== 0) {
+        dispatch(openModal('CONFIRM', {
+          message: intl.formatMessage(messages.replyMessage),
+          confirm: intl.formatMessage(messages.replyConfirm),
+          onConfirm: () => dispatch(replyCompose(status, router)),
+        }));
+      } else {
+        dispatch(replyCompose(status, router));
+      }
+    });
+  },
+
+  delete () {
+    dispatch(deleteConversation(conversationId));
+  },
+
+  onMute (status) {
+    if (status.get('muted')) {
+      dispatch(unmuteStatus(status.get('id')));
+    } else {
+      dispatch(muteStatus(status.get('id')));
+    }
+  },
+
+  onToggleHidden (status) {
+    if (status.get('hidden')) {
+      dispatch(revealStatus(status.get('id')));
+    } else {
+      dispatch(hideStatus(status.get('id')));
+    }
+  },
+
 });
 
-export default connect(mapStateToProps, mapDispatchToProps)(Conversation);
+export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(Conversation));
diff --git a/app/javascript/mastodon/features/emoji/emoji.js b/app/javascript/mastodon/features/emoji/emoji.js
index 359bb7ffd..cd10e20b7 100644
--- a/app/javascript/mastodon/features/emoji/emoji.js
+++ b/app/javascript/mastodon/features/emoji/emoji.js
@@ -99,4 +99,4 @@ export const buildCustomEmojis = (customEmojis) => {
   return emojis;
 };
 
-export const categoriesFromEmojis = customEmojis => customEmojis.reduce((set, emoji) => set.add(emoji.get('category') ? `custom-${emoji.get('category')}` : 'custom'), new Set());
+export const categoriesFromEmojis = customEmojis => customEmojis.reduce((set, emoji) => set.add(emoji.get('category') ? `custom-${emoji.get('category')}` : 'custom'), new Set(['custom']));
diff --git a/app/javascript/mastodon/features/favourites/index.js b/app/javascript/mastodon/features/favourites/index.js
index 62d3c2f06..90c26f0c3 100644
--- a/app/javascript/mastodon/features/favourites/index.js
+++ b/app/javascript/mastodon/features/favourites/index.js
@@ -27,7 +27,9 @@ class Favourites extends ImmutablePureComponent {
   };
 
   componentWillMount () {
-    this.props.dispatch(fetchFavourites(this.props.params.statusId));
+    if (!this.props.accountIds) {
+      this.props.dispatch(fetchFavourites(this.props.params.statusId));
+    }
   }
 
   componentWillReceiveProps (nextProps) {
diff --git a/app/javascript/mastodon/features/followers/index.js b/app/javascript/mastodon/features/followers/index.js
index 3913bf8d0..9e635d250 100644
--- a/app/javascript/mastodon/features/followers/index.js
+++ b/app/javascript/mastodon/features/followers/index.js
@@ -40,8 +40,10 @@ class Followers extends ImmutablePureComponent {
   };
 
   componentWillMount () {
-    this.props.dispatch(fetchAccount(this.props.params.accountId));
-    this.props.dispatch(fetchFollowers(this.props.params.accountId));
+    if (!this.props.accountIds) {
+      this.props.dispatch(fetchAccount(this.props.params.accountId));
+      this.props.dispatch(fetchFollowers(this.props.params.accountId));
+    }
   }
 
   componentWillReceiveProps (nextProps) {
diff --git a/app/javascript/mastodon/features/following/index.js b/app/javascript/mastodon/features/following/index.js
index 8e126f4c3..284ae2c11 100644
--- a/app/javascript/mastodon/features/following/index.js
+++ b/app/javascript/mastodon/features/following/index.js
@@ -40,8 +40,10 @@ class Following extends ImmutablePureComponent {
   };
 
   componentWillMount () {
-    this.props.dispatch(fetchAccount(this.props.params.accountId));
-    this.props.dispatch(fetchFollowing(this.props.params.accountId));
+    if (!this.props.accountIds) {
+      this.props.dispatch(fetchAccount(this.props.params.accountId));
+      this.props.dispatch(fetchFollowing(this.props.params.accountId));
+    }
   }
 
   componentWillReceiveProps (nextProps) {
diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js
index f6d90580b..67ec7665b 100644
--- a/app/javascript/mastodon/features/getting_started/index.js
+++ b/app/javascript/mastodon/features/getting_started/index.js
@@ -77,16 +77,14 @@ class GettingStarted extends ImmutablePureComponent {
   };
 
   componentDidMount () {
-    const { myAccount, fetchFollowRequests, multiColumn } = this.props;
+    const { fetchFollowRequests, multiColumn } = this.props;
 
     if (!multiColumn && window.innerWidth >= NAVIGATION_PANEL_BREAKPOINT) {
       this.context.router.history.replace('/timelines/home');
       return;
     }
 
-    if (myAccount.get('locked')) {
-      fetchFollowRequests();
-    }
+    fetchFollowRequests();
   }
 
   render () {
@@ -134,7 +132,7 @@ class GettingStarted extends ImmutablePureComponent {
 
     height += 48*3;
 
-    if (myAccount.get('locked')) {
+    if (myAccount.get('locked') || unreadFollowRequests > 0) {
       navItems.push(<ColumnLink key={i++} icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
       height += 48;
     }
diff --git a/app/javascript/mastodon/features/notifications/components/filter_bar.js b/app/javascript/mastodon/features/notifications/components/filter_bar.js
index 3f3e6ab7d..2fd28d832 100644
--- a/app/javascript/mastodon/features/notifications/components/filter_bar.js
+++ b/app/javascript/mastodon/features/notifications/components/filter_bar.js
@@ -64,7 +64,7 @@ class FilterBar extends React.PureComponent {
           onClick={this.onClick('mention')}
           title={intl.formatMessage(tooltips.mentions)}
         >
-          <Icon id='at' fixedWidth />
+          <Icon id='reply-all' fixedWidth />
         </button>
         <button
           className={selectedFilter === 'favourite' ? 'active' : ''}
diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js
index 7e5de0613..d16a0f33a 100644
--- a/app/javascript/mastodon/features/notifications/index.js
+++ b/app/javascript/mastodon/features/notifications/index.js
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import Column from '../../components/column';
 import ColumnHeader from '../../components/column_header';
-import { expandNotifications, scrollTopNotifications, loadPending } from '../../actions/notifications';
+import { expandNotifications, scrollTopNotifications, loadPending, mountNotifications, unmountNotifications } from '../../actions/notifications';
 import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 import NotificationContainer from './containers/notification_container';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
@@ -66,11 +66,16 @@ class Notifications extends React.PureComponent {
     trackScroll: true,
   };
 
+  componentWillMount() {
+    this.props.dispatch(mountNotifications());
+  }
+
   componentWillUnmount () {
     this.handleLoadOlder.cancel();
     this.handleScrollToTop.cancel();
     this.handleScroll.cancel();
     this.props.dispatch(scrollTopNotifications(false));
+    this.props.dispatch(unmountNotifications());
   }
 
   handleLoadGap = (maxId) => {
diff --git a/app/javascript/mastodon/features/reblogs/index.js b/app/javascript/mastodon/features/reblogs/index.js
index 229f626b3..7edcf1968 100644
--- a/app/javascript/mastodon/features/reblogs/index.js
+++ b/app/javascript/mastodon/features/reblogs/index.js
@@ -27,7 +27,9 @@ class Reblogs extends ImmutablePureComponent {
   };
 
   componentWillMount () {
-    this.props.dispatch(fetchReblogs(this.props.params.statusId));
+    if (!this.props.accountIds) {
+      this.props.dispatch(fetchReblogs(this.props.params.statusId));
+    }
   }
 
   componentWillReceiveProps(nextProps) {
diff --git a/app/javascript/mastodon/features/status/containers/detailed_status_container.js b/app/javascript/mastodon/features/status/containers/detailed_status_container.js
index 61e0c428a..333c295dc 100644
--- a/app/javascript/mastodon/features/status/containers/detailed_status_container.js
+++ b/app/javascript/mastodon/features/status/containers/detailed_status_container.js
@@ -1,4 +1,3 @@
-import React from 'react';
 import { connect } from 'react-redux';
 import DetailedStatus from '../components/detailed_status';
 import { makeGetStatus } from '../../../selectors';
@@ -15,7 +14,6 @@ import {
   pin,
   unpin,
 } from '../../../actions/interactions';
-import { blockAccount } from '../../../actions/accounts';
 import {
   muteStatus,
   unmuteStatus,
@@ -24,9 +22,10 @@ import {
   revealStatus,
 } from '../../../actions/statuses';
 import { initMuteModal } from '../../../actions/mutes';
+import { initBlockModal } from '../../../actions/blocks';
 import { initReport } from '../../../actions/reports';
 import { openModal } from '../../../actions/modal';
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { defineMessages, injectIntl } from 'react-intl';
 import { boostModal, deleteModal } from '../../../initial_state';
 import { showAlertForError } from '../../../actions/alerts';
 
@@ -35,10 +34,8 @@ const messages = defineMessages({
   deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
   redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
   redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: '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.' },
-  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
   replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
   replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
-  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
 });
 
 const makeMapStateToProps = () => {
@@ -138,16 +135,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
 
   onBlock (status) {
     const account = status.get('account');
-    dispatch(openModal('CONFIRM', {
-      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
-      confirm: intl.formatMessage(messages.blockConfirm),
-      onConfirm: () => dispatch(blockAccount(account.get('id'))),
-      secondary: intl.formatMessage(messages.blockAndReport),
-      onSecondary: () => {
-        dispatch(blockAccount(account.get('id')));
-        dispatch(initReport(account, status));
-      },
-    }));
+    dispatch(initBlockModal(account));
   },
 
   onReport (status) {
diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js
index f78a9489a..029057d40 100644
--- a/app/javascript/mastodon/features/status/index.js
+++ b/app/javascript/mastodon/features/status/index.js
@@ -23,7 +23,6 @@ import {
   mentionCompose,
   directCompose,
 } from '../../actions/compose';
-import { blockAccount } from '../../actions/accounts';
 import {
   muteStatus,
   unmuteStatus,
@@ -32,6 +31,7 @@ import {
   revealStatus,
 } from '../../actions/statuses';
 import { initMuteModal } from '../../actions/mutes';
+import { initBlockModal } from '../../actions/blocks';
 import { initReport } from '../../actions/reports';
 import { makeGetStatus } from '../../selectors';
 import { ScrollContainer } from 'react-router-scroll-4';
@@ -39,7 +39,7 @@ import ColumnBackButton from '../../components/column_back_button';
 import ColumnHeader from '../../components/column_header';
 import StatusContainer from '../../containers/status_container';
 import { openModal } from '../../actions/modal';
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { HotKeys } from 'react-hotkeys';
 import { boostModal, deleteModal } from '../../initial_state';
@@ -52,13 +52,11 @@ const messages = defineMessages({
   deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' },
   redraftConfirm: { id: 'confirmations.redraft.confirm', defaultMessage: 'Delete & redraft' },
   redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: '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.' },
-  blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
   revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },
   hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },
   detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' },
   replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
   replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
-  blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
 });
 
 const makeMapStateToProps = () => {
@@ -296,19 +294,9 @@ class Status extends ImmutablePureComponent {
   }
 
   handleBlockClick = (status) => {
-    const { dispatch, intl } = this.props;
+    const { dispatch } = this.props;
     const account = status.get('account');
-
-    dispatch(openModal('CONFIRM', {
-      message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
-      confirm: intl.formatMessage(messages.blockConfirm),
-      onConfirm: () => dispatch(blockAccount(account.get('id'))),
-      secondary: intl.formatMessage(messages.blockAndReport),
-      onSecondary: () => {
-        dispatch(blockAccount(account.get('id')));
-        dispatch(initReport(account, status));
-      },
-    }));
+    dispatch(initBlockModal(account));
   }
 
   handleReport = (status) => {
diff --git a/app/javascript/mastodon/features/ui/components/block_modal.js b/app/javascript/mastodon/features/ui/components/block_modal.js
new file mode 100644
index 000000000..a07baeaa6
--- /dev/null
+++ b/app/javascript/mastodon/features/ui/components/block_modal.js
@@ -0,0 +1,103 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { injectIntl, FormattedMessage } from 'react-intl';
+import { makeGetAccount } from '../../../selectors';
+import Button from '../../../components/button';
+import { closeModal } from '../../../actions/modal';
+import { blockAccount } from '../../../actions/accounts';
+import { initReport } from '../../../actions/reports';
+
+
+const makeMapStateToProps = () => {
+  const getAccount = makeGetAccount();
+
+  const mapStateToProps = state => ({
+    account: getAccount(state, state.getIn(['blocks', 'new', 'account_id'])),
+  });
+
+  return mapStateToProps;
+};
+
+const mapDispatchToProps = dispatch => {
+  return {
+    onConfirm(account) {
+      dispatch(blockAccount(account.get('id')));
+    },
+
+    onBlockAndReport(account) {
+      dispatch(blockAccount(account.get('id')));
+      dispatch(initReport(account));
+    },
+
+    onClose() {
+      dispatch(closeModal());
+    },
+  };
+};
+
+export default @connect(makeMapStateToProps, mapDispatchToProps)
+@injectIntl
+class BlockModal extends React.PureComponent {
+
+  static propTypes = {
+    account: PropTypes.object.isRequired,
+    onClose: PropTypes.func.isRequired,
+    onBlockAndReport: PropTypes.func.isRequired,
+    onConfirm: PropTypes.func.isRequired,
+    intl: PropTypes.object.isRequired,
+  };
+
+  componentDidMount() {
+    this.button.focus();
+  }
+
+  handleClick = () => {
+    this.props.onClose();
+    this.props.onConfirm(this.props.account);
+  }
+
+  handleSecondary = () => {
+    this.props.onClose();
+    this.props.onBlockAndReport(this.props.account);
+  }
+
+  handleCancel = () => {
+    this.props.onClose();
+  }
+
+  setRef = (c) => {
+    this.button = c;
+  }
+
+  render () {
+    const { account } = this.props;
+
+    return (
+      <div className='modal-root__modal block-modal'>
+        <div className='block-modal__container'>
+          <p>
+            <FormattedMessage
+              id='confirmations.block.message'
+              defaultMessage='Are you sure you want to block {name}?'
+              values={{ name: <strong>@{account.get('acct')}</strong> }}
+            />
+          </p>
+        </div>
+
+        <div className='block-modal__action-bar'>
+          <Button onClick={this.handleCancel} className='block-modal__cancel-button'>
+            <FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
+          </Button>
+          <Button onClick={this.handleSecondary} className='confirmation-modal__secondary-button'>
+            <FormattedMessage id='confirmations.block.block_and_report' defaultMessage='Block & Report' />
+          </Button>
+          <Button onClick={this.handleClick} ref={this.setRef}>
+            <FormattedMessage id='confirmations.block.confirm' defaultMessage='Block' />
+          </Button>
+        </div>
+      </div>
+    );
+  }
+
+}
diff --git a/app/javascript/mastodon/features/ui/components/focal_point_modal.js b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
index 7891d6690..1ab79a21d 100644
--- a/app/javascript/mastodon/features/ui/components/focal_point_modal.js
+++ b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
@@ -173,7 +173,17 @@ class FocalPointModal extends ImmutablePureComponent {
         langPath: `${assetHost}/ocr/lang-data`,
       });
 
-      worker.recognize(media.get('url'))
+      let media_url = media.get('file');
+
+      if (window.URL && URL.createObjectURL) {
+        try {
+          media_url = URL.createObjectURL(media.get('file'));
+        } catch (error) {
+          console.error(error);
+        }
+      }
+
+      worker.recognize(media_url)
         .progress(({ progress }) => this.setState({ progress }))
         .finally(() => worker.terminate())
         .then(({ text }) => this.setState({ description: removeExtraLineBreaks(text), dirty: true, detecting: false }))
diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js
index 06f9e1bc4..58d3ba8db 100644
--- a/app/javascript/mastodon/features/ui/components/modal_root.js
+++ b/app/javascript/mastodon/features/ui/components/modal_root.js
@@ -1,6 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import Base from '../../../components/modal_root';
+import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
+import Base from 'mastodon/components/modal_root';
 import BundleContainer from '../containers/bundle_container';
 import BundleModalError from './bundle_modal_error';
 import ModalLoading from './modal_loading';
@@ -12,6 +13,7 @@ import ConfirmationModal from './confirmation_modal';
 import FocalPointModal from './focal_point_modal';
 import {
   MuteModal,
+  BlockModal,
   ReportModal,
   EmbedModal,
   ListEditor,
@@ -24,6 +26,7 @@ const MODAL_COMPONENTS = {
   'BOOST': () => Promise.resolve({ default: BoostModal }),
   'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
   'MUTE': MuteModal,
+  'BLOCK': BlockModal,
   'REPORT': ReportModal,
   'ACTIONS': () => Promise.resolve({ default: ActionsModal }),
   'EMBED': EmbedModal,
@@ -32,28 +35,6 @@ const MODAL_COMPONENTS = {
   'LIST_ADDER':ListAdder,
 };
 
-let cachedScrollbarWidth = null;
-
-export const getScrollbarWidth = () => {
-  if (cachedScrollbarWidth !== null) {
-    return cachedScrollbarWidth;
-  }
-
-  const outer = document.createElement('div');
-  outer.style.visibility = 'hidden';
-  outer.style.overflow = 'scroll';
-  document.body.appendChild(outer);
-
-  const inner = document.createElement('div');
-  outer.appendChild(inner);
-
-  const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
-  cachedScrollbarWidth = scrollbarWidth;
-  outer.parentNode.removeChild(outer);
-
-  return scrollbarWidth;
-};
-
 export default class ModalRoot extends React.PureComponent {
 
   static propTypes = {
diff --git a/app/javascript/mastodon/features/ui/components/mute_modal.js b/app/javascript/mastodon/features/ui/components/mute_modal.js
index ac356b42a..c364c5ba2 100644
--- a/app/javascript/mastodon/features/ui/components/mute_modal.js
+++ b/app/javascript/mastodon/features/ui/components/mute_modal.js
@@ -11,7 +11,6 @@ import { toggleHideNotifications } from '../../../actions/mutes';
 
 const mapStateToProps = state => {
   return {
-    isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
     account: state.getIn(['mutes', 'new', 'account']),
     notifications: state.getIn(['mutes', 'new', 'notifications']),
   };
@@ -38,7 +37,6 @@ export default @connect(mapStateToProps, mapDispatchToProps)
 class MuteModal extends React.PureComponent {
 
   static propTypes = {
-    isSubmitting: PropTypes.bool.isRequired,
     account: PropTypes.object.isRequired,
     notifications: PropTypes.bool.isRequired,
     onClose: PropTypes.func.isRequired,
@@ -81,11 +79,16 @@ class MuteModal extends React.PureComponent {
               values={{ name: <strong>@{account.get('acct')}</strong> }}
             />
           </p>
-          <div>
-            <label htmlFor='mute-modal__hide-notifications-checkbox'>
+          <p className='mute-modal__explanation'>
+            <FormattedMessage
+              id='confirmations.mute.explanation'
+              defaultMessage='This will hide posts from them and posts mentioning them, but it will still allow them to see your posts follow you.'
+            />
+          </p>
+          <div className='setting-toggle'>
+            <Toggle id='mute-modal__hide-notifications-checkbox' checked={notifications} onChange={this.toggleNotifications} />
+            <label className='setting-toggle__label' htmlFor='mute-modal__hide-notifications-checkbox'>
               <FormattedMessage id='mute_modal.hide_notifications' defaultMessage='Hide notifications from this user?' />
-              {' '}
-              <Toggle id='mute-modal__hide-notifications-checkbox' checked={notifications} onChange={this.toggleNotifications} />
             </label>
           </div>
         </div>
diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js
index 0084c1510..bb0fcb859 100644
--- a/app/javascript/mastodon/features/ui/util/async-components.js
+++ b/app/javascript/mastodon/features/ui/util/async-components.js
@@ -106,6 +106,10 @@ export function MuteModal () {
   return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal');
 }
 
+export function BlockModal () {
+  return import(/* webpackChunkName: "modals/block_modal" */'../components/block_modal');
+}
+
 export function ReportModal () {
   return import(/* webpackChunkName: "modals/report_modal" */'../components/report_modal');
 }
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index ce66a5d1c..8e2efe136 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -7,7 +7,7 @@
   "account.cancel_follow_request": "إلغاء طلب المتابَعة",
   "account.direct": "رسالة خاصة إلى @{name}",
   "account.domain_blocked": "النطاق مخفي",
-  "account.edit_profile": "تعديل الملف الشخصي",
+  "account.edit_profile": "تعديل الملف التعريفي",
   "account.endorse": "أوصِ به على صفحتك",
   "account.follow": "تابِع",
   "account.followers": "متابعون",
@@ -30,11 +30,11 @@
   "account.posts_with_replies": "التبويقات و الردود",
   "account.report": "ابلِغ عن @{name}",
   "account.requested": "في انتظار الموافقة. اضْغَطْ/ي لإلغاء طلب المتابعة",
-  "account.share": "مشاركة حساب @{name}",
+  "account.share": "شارك ملف تعريف @{name}",
   "account.show_reblogs": "اعرض ترقيات @{name}",
   "account.unblock": "إلغاء الحظر عن @{name}",
   "account.unblock_domain": "فك الخْفى عن {domain}",
-  "account.unendorse": "أزل ترويجه مِن الملف الشخصي",
+  "account.unendorse": "أزل ترويجه مِن الملف التعريفي",
   "account.unfollow": "إلغاء المتابعة",
   "account.unmute": "إلغاء الكتم عن @{name}",
   "account.unmute_notifications": "إلغاء كتم إخطارات @{name}",
@@ -53,7 +53,7 @@
   "column.blocks": "الحسابات المحجوبة",
   "column.community": "الخيط العام المحلي",
   "column.direct": "الرسائل المباشرة",
-  "column.directory": "Browse profiles",
+  "column.directory": "استعرض الملفات التعريفية",
   "column.domain_blocks": "النطاقات المخفية",
   "column.favourites": "المفضلة",
   "column.follow_requests": "طلبات المتابعة",
@@ -63,7 +63,7 @@
   "column.notifications": "الإخطارات",
   "column.pins": "التبويقات المثبتة",
   "column.public": "الخيط العام الموحد",
-  "column.status": "Toot",
+  "column.status": "تبويق",
   "column_back_button.label": "العودة",
   "column_header.hide_settings": "إخفاء الإعدادات",
   "column_header.moveLeft_settings": "نقل القائمة إلى اليسار",
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "الرد في الحين سوف يُعيد كتابة الرسالة التي أنت بصدد كتابتها. متأكد من أنك تريد المواصلة؟",
   "confirmations.unfollow.confirm": "إلغاء المتابعة",
   "confirmations.unfollow.message": "متأكد من أنك تريد إلغاء متابعة {name} ؟",
+  "conversation.delete": "احذف المحادثة",
+  "conversation.mark_as_read": "اعتبرها كمقروءة",
+  "conversation.open": "اعرض المحادثة",
+  "conversation.with": "بـ {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "الوافدون الجُدد",
@@ -132,7 +136,7 @@
   "emoji_button.symbols": "رموز",
   "emoji_button.travel": "الأماكن والسفر",
   "empty_column.account_timeline": "ليس هناك تبويقات!",
-  "empty_column.account_unavailable": "الملف الشخصي غير متوفر",
+  "empty_column.account_unavailable": "الملف التعريفي غير متوفر",
   "empty_column.blocks": "لم تقم بحظر أي مستخدِم بعد.",
   "empty_column.community": "الخط العام المحلي فارغ. أكتب شيئا ما للعامة كبداية!",
   "empty_column.direct": "لم تتلق أية رسالة خاصة مباشِرة بعد. سوف يتم عرض الرسائل المباشرة هنا إن قمت بإرسال واحدة أو تلقيت البعض منها.",
@@ -151,7 +155,7 @@
   "follow_request.authorize": "ترخيص",
   "follow_request.reject": "رفض",
   "getting_started.developers": "المُطوِّرون",
-  "getting_started.directory": "دليل المستخدِمين والمستخدِمات",
+  "getting_started.directory": "دليل الصفحات التعريفية",
   "getting_started.documentation": "الدليل",
   "getting_started.heading": "استعدّ للبدء",
   "getting_started.invite": "دعوة أشخاص",
@@ -190,7 +194,7 @@
   "introduction.interactions.reply.text": "يمكنكم الرد على تبويقاتكم و تبويقات الآخرين على شكل سلسلة محادثة.",
   "introduction.welcome.action": "هيا بنا!",
   "introduction.welcome.headline": "الخطوات الأولى",
-  "introduction.welcome.text": "مرحبا بكم على الفديفرس! بعد لحظات قليلة ، سيكون بمقدوركم بث رسائل والتحدث إلى أصدقائكم عبر تشكيلة واسعة من الخوادم المختلفة. هذا الخادم ، {domain} ، يستضيف ملفكم الشخصي ، لذا يجب تذكر اسمه جيدا.",
+  "introduction.welcome.text": "مرحبا بكم على الفديفرس! بعد لحظات قليلة ، سيكون بمقدوركم بث رسائل والتحدث إلى أصدقائكم عبر تشكيلة واسعة من الخوادم المختلفة. هذا الخادم ، {domain} ، يستضيف صفحتكم التعريفية ، لذا يجب تذكر اسمه جيدا.",
   "keyboard_shortcuts.back": "للعودة",
   "keyboard_shortcuts.blocked": "لفتح قائمة المستخدمين المحظورين",
   "keyboard_shortcuts.boost": "للترقية",
@@ -210,10 +214,10 @@
   "keyboard_shortcuts.local": "لفتح الخيط العام المحلي",
   "keyboard_shortcuts.mention": "لذِكر الناشر",
   "keyboard_shortcuts.muted": "لفتح قائمة المستخدِمين المكتومين",
-  "keyboard_shortcuts.my_profile": "لفتح ملفك الشخصي",
+  "keyboard_shortcuts.my_profile": "لفتح ملفك التعريفي",
   "keyboard_shortcuts.notifications": "لفتح عمود الإشعارات",
   "keyboard_shortcuts.pinned": "لفتح قائمة التبويقات المدبسة",
-  "keyboard_shortcuts.profile": "لفتح رابط الناشر",
+  "keyboard_shortcuts.profile": "لفتح الملف التعريفي للناشر",
   "keyboard_shortcuts.reply": "للردّ",
   "keyboard_shortcuts.requests": "لفتح قائمة طلبات المتابعة",
   "keyboard_shortcuts.search": "للتركيز على البحث",
@@ -249,7 +253,7 @@
   "navigation_bar.direct": "الرسائل المباشِرة",
   "navigation_bar.discover": "اكتشف",
   "navigation_bar.domain_blocks": "النطاقات المخفية",
-  "navigation_bar.edit_profile": "تعديل الملف الشخصي",
+  "navigation_bar.edit_profile": "عدّل الملف التعريفي",
   "navigation_bar.favourites": "المفضلة",
   "navigation_bar.filters": "الكلمات المكتومة",
   "navigation_bar.follow_requests": "طلبات المتابعة",
@@ -295,6 +299,7 @@
   "poll.refresh": "تحديث",
   "poll.total_votes": "{count, plural, one {# صوت} other {# أصوات}}",
   "poll.vote": "صَوّت",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "إضافة استطلاع للرأي",
   "poll_button.remove_poll": "إزالة استطلاع الرأي",
   "privacy.change": "اضبط خصوصية المنشور",
@@ -351,7 +356,7 @@
   "status.mute": "أكتم @{name}",
   "status.mute_conversation": "كتم المحادثة",
   "status.open": "وسع هذه المشاركة",
-  "status.pin": "تدبيس على الملف الشخصي",
+  "status.pin": "دبّسه على الصفحة التعريفية",
   "status.pinned": "تبويق مثبَّت",
   "status.read_more": "اقرأ المزيد",
   "status.reblog": "رَقِّي",
@@ -371,7 +376,7 @@
   "status.show_thread": "الكشف عن المحادثة",
   "status.uncached_media_warning": "غير متوفر",
   "status.unmute_conversation": "فك الكتم عن المحادثة",
-  "status.unpin": "فك التدبيس من الملف الشخصي",
+  "status.unpin": "فك التدبيس من الصفحة التعريفية",
   "suggestions.dismiss": "إلغاء الاقتراح",
   "suggestions.header": "يمكن أن يهمك…",
   "tabs_bar.federated_timeline": "الموحَّد",
@@ -400,7 +405,7 @@
   "upload_modal.detect_text": "Detect text from picture",
   "upload_modal.edit_media": "تعديل الوسائط",
   "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
-  "upload_modal.preview_label": "Preview ({ratio})",
+  "upload_modal.preview_label": "معاينة ({ratio})",
   "upload_progress.label": "يرفع...",
   "video.close": "إغلاق الفيديو",
   "video.exit_fullscreen": "الخروج من وضع الشاشة المليئة",
diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json
index 2ef693fcb..76721749c 100644
--- a/app/javascript/mastodon/locales/ast.json
+++ b/app/javascript/mastodon/locales/ast.json
@@ -111,6 +111,10 @@
   "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": "¿De xuru que quies dexar de siguir a {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 309f04513..b230d1863 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -1,12 +1,12 @@
 {
-  "account.add_or_remove_from_list": "Add or Remove from lists",
-  "account.badges.bot": "Bot",
+  "account.add_or_remove_from_list": "Добави или премахни от списъците",
+  "account.badges.bot": "бот",
   "account.block": "Блокирай",
-  "account.block_domain": "Hide everything from {domain}",
-  "account.blocked": "Blocked",
+  "account.block_domain": "скрий всичко от (домейн)",
+  "account.blocked": "Блокирани",
   "account.cancel_follow_request": "Cancel follow request",
   "account.direct": "Direct Message @{name}",
-  "account.domain_blocked": "Domain hidden",
+  "account.domain_blocked": "Скрит домейн",
   "account.edit_profile": "Редактирай профила си",
   "account.endorse": "Feature on profile",
   "account.follow": "Последвай",
@@ -45,7 +45,7 @@
   "autosuggest_hashtag.per_week": "{count} per week",
   "boost_modal.combo": "You can press {combo} to skip this next time",
   "bundle_column_error.body": "Something went wrong while loading this component.",
-  "bundle_column_error.retry": "Try again",
+  "bundle_column_error.retry": "Опитай отново",
   "bundle_column_error.title": "Network error",
   "bundle_modal_error.close": "Close",
   "bundle_modal_error.message": "Something went wrong while loading this component.",
@@ -58,7 +58,7 @@
   "column.favourites": "Favourites",
   "column.follow_requests": "Follow requests",
   "column.home": "Начало",
-  "column.lists": "Lists",
+  "column.lists": "Списъци",
   "column.mutes": "Muted users",
   "column.notifications": "Известия",
   "column.pins": "Pinned toot",
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json
index e4984a118..8109d97eb 100644
--- a/app/javascript/mastodon/locales/bn.json
+++ b/app/javascript/mastodon/locales/bn.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "এখন মতামত লিখতে গেলে আপনার এখন যেটা লিখছেন সেটা মুছে যাবে। আপনি নি নিশ্চিত এটা করতে চান ?",
   "confirmations.unfollow.confirm": "অনুসরণ করা বাতিল করতে",
   "confirmations.unfollow.message": "আপনি কি নিশ্চিত {name} কে আর অনুসরণ করতে চান না ?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "বদলেছে কিনা দেখতে",
   "poll.total_votes": "{count, plural, one {# ভোট} other {# ভোট}}",
   "poll.vote": "ভোট",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "একটা নির্বাচন যোগ করতে",
   "poll_button.remove_poll": "নির্বাচন বাদ দিতে",
   "privacy.change": "লেখার গোপনীয়তা অবস্থা ঠিক করতে",
diff --git a/app/javascript/mastodon/locales/br.json b/app/javascript/mastodon/locales/br.json
index 2de037f16..fbe8020bd 100644
--- a/app/javascript/mastodon/locales/br.json
+++ b/app/javascript/mastodon/locales/br.json
@@ -1,60 +1,60 @@
 {
-  "account.add_or_remove_from_list": "Add or Remove from lists",
-  "account.badges.bot": "Bot",
-  "account.block": "Block @{name}",
-  "account.block_domain": "Hide everything from {domain}",
-  "account.blocked": "Blocked",
-  "account.cancel_follow_request": "Cancel follow request",
-  "account.direct": "Direct message @{name}",
-  "account.domain_blocked": "Domain hidden",
-  "account.edit_profile": "Edit profile",
-  "account.endorse": "Feature on profile",
-  "account.follow": "Follow",
-  "account.followers": "Followers",
-  "account.followers.empty": "No one follows this user yet.",
-  "account.follows": "Follows",
+  "account.add_or_remove_from_list": "Ouzhpenn pe lemel ag ar listennadoù",
+  "account.badges.bot": "Robot",
+  "account.block": "Stankañ @{name}",
+  "account.block_domain": "Kuzh kement tra a {domain}",
+  "account.blocked": "Stanket",
+  "account.cancel_follow_request": "Nullañ ar pedad heuliañ",
+  "account.direct": "Kas ur c'hemennad da @{name}",
+  "account.domain_blocked": "Domani kuzhet",
+  "account.edit_profile": "Aozañ ar profil",
+  "account.endorse": "Lakaat war-wel war ar profil",
+  "account.follow": "Heuliañ",
+  "account.followers": "Heilour·ezed·ion",
+  "account.followers.empty": "Den na heul an implijour-mañ c'hoazh.",
+  "account.follows": "Koumanantoù",
   "account.follows.empty": "This user doesn't follow anyone yet.",
-  "account.follows_you": "Follows you",
-  "account.hide_reblogs": "Hide boosts from @{name}",
-  "account.last_status": "Last active",
+  "account.follows_you": "Ho heul",
+  "account.hide_reblogs": "Kuzh toudoù skignet gant @{name}",
+  "account.last_status": "Oberiantiz zivezhañ",
   "account.link_verified_on": "Ownership of this link was checked on {date}",
   "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.",
   "account.media": "Media",
-  "account.mention": "Mention @{name}",
-  "account.moved_to": "{name} has moved to:",
-  "account.mute": "Mute @{name}",
-  "account.mute_notifications": "Mute notifications from @{name}",
-  "account.muted": "Muted",
-  "account.never_active": "Never",
-  "account.posts": "Toots",
-  "account.posts_with_replies": "Toots and replies",
-  "account.report": "Report @{name}",
+  "account.mention": "Menegiñ @{name}",
+  "account.moved_to": "Dilojet en·he deus {name} da:",
+  "account.mute": "Kuzhat @{name}",
+  "account.mute_notifications": "Kuzh kemennoù a @{name}",
+  "account.muted": "Kuzhet",
+  "account.never_active": "Birviken",
+  "account.posts": "Toudoù",
+  "account.posts_with_replies": "Toudoù ha respontoù",
+  "account.report": "Disklêriañ @{name}",
   "account.requested": "Awaiting approval",
-  "account.share": "Share @{name}'s profile",
-  "account.show_reblogs": "Show boosts from @{name}",
-  "account.unblock": "Unblock @{name}",
-  "account.unblock_domain": "Unhide {domain}",
+  "account.share": "Skignañ profil @{name}",
+  "account.show_reblogs": "Diskouez toudoù a @{name}",
+  "account.unblock": "Distankañ @{name}",
+  "account.unblock_domain": "Diguzh {domain}",
   "account.unendorse": "Don't feature on profile",
-  "account.unfollow": "Unfollow",
-  "account.unmute": "Unmute @{name}",
-  "account.unmute_notifications": "Unmute notifications from @{name}",
+  "account.unfollow": "Diheuliañ",
+  "account.unmute": "Diguzhat @{name}",
+  "account.unmute_notifications": "Diguzhat kemennoù a @{name}",
   "alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
   "alert.rate_limited.title": "Rate limited",
-  "alert.unexpected.message": "An unexpected error occurred.",
-  "alert.unexpected.title": "Oops!",
-  "autosuggest_hashtag.per_week": "{count} per week",
+  "alert.unexpected.message": "Ur fazi dic'hortozet zo degouezhet.",
+  "alert.unexpected.title": "C'hem !",
+  "autosuggest_hashtag.per_week": "{count} bep sizhun",
   "boost_modal.combo": "You can press {combo} to skip this next time",
   "bundle_column_error.body": "Something went wrong while loading this component.",
-  "bundle_column_error.retry": "Try again",
-  "bundle_column_error.title": "Network error",
-  "bundle_modal_error.close": "Close",
+  "bundle_column_error.retry": "Klask endro",
+  "bundle_column_error.title": "Fazi rouedad",
+  "bundle_modal_error.close": "Serriñ",
   "bundle_modal_error.message": "Something went wrong while loading this component.",
-  "bundle_modal_error.retry": "Try again",
-  "column.blocks": "Blocked users",
-  "column.community": "Local timeline",
-  "column.direct": "Direct messages",
-  "column.directory": "Browse profiles",
-  "column.domain_blocks": "Hidden domains",
+  "bundle_modal_error.retry": "Klask endro",
+  "column.blocks": "Implijour·ezed·ion stanket",
+  "column.community": "Red-amzer lec'hel",
+  "column.direct": "Kemennadoù prevez",
+  "column.directory": "Mont a-dreuz ar profiloù",
+  "column.domain_blocks": "Domani kuzhet",
   "column.favourites": "Favourites",
   "column.follow_requests": "Follow requests",
   "column.home": "Home",
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index 77f84ac7d..5b05c09d5 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Responen ara es sobreescriurà el missatge que estàs editant. Estàs segur que vols continuar?",
   "confirmations.unfollow.confirm": "Deixa de seguir",
   "confirmations.unfollow.message": "Estàs segur que vols deixar de seguir {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Actualitza",
   "poll.total_votes": "{count, plural, one {# vot} other {# vots}}",
   "poll.vote": "Vota",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Afegeix una enquesta",
   "poll_button.remove_poll": "Elimina l'enquesta",
   "privacy.change": "Ajusta l'estat de privacitat",
diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json
index d95f32b18..7ebe08cf5 100644
--- a/app/javascript/mastodon/locales/co.json
+++ b/app/javascript/mastodon/locales/co.json
@@ -63,7 +63,7 @@
   "column.notifications": "Nutificazione",
   "column.pins": "Statuti puntarulati",
   "column.public": "Linea pubblica glubale",
-  "column.status": "Toot",
+  "column.status": "Statutu",
   "column_back_button.label": "Ritornu",
   "column_header.hide_settings": "Piattà i parametri",
   "column_header.moveLeft_settings": "Spiazzà à manca",
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Risponde avà sguasserà u missaghju chì scrivite. Site sicuru·a chì vulete cuntinuà?",
   "confirmations.unfollow.confirm": "Disabbunassi",
   "confirmations.unfollow.message": "Site sicuru·a ch'ùn vulete più siguità @{name}?",
+  "conversation.delete": "Sguassà a cunversazione",
+  "conversation.mark_as_read": "Marcà cum'è lettu",
+  "conversation.open": "Vede a cunversazione",
+  "conversation.with": "Cù {names}",
   "directory.federated": "Da u fediverse cunisciutu",
   "directory.local": "Solu da {domain}",
   "directory.new_arrivals": "Ultimi arrivi",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Bàsichi",
   "home.column_settings.show_reblogs": "Vede e spartere",
   "home.column_settings.show_replies": "Vede e risposte",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Attualizà in tempu reale",
   "intervals.full.days": "{number, plural, one {# ghjornu} other {# ghjorni}}",
   "intervals.full.hours": "{number, plural, one {# ora} other {# ore}}",
   "intervals.full.minutes": "{number, plural, one {# minuta} other {# minute}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Preferenze",
   "navigation_bar.public_timeline": "Linea pubblica glubale",
   "navigation_bar.security": "Sicurità",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "è {count, plural, one {# altru} other {# altri}}",
   "notification.favourite": "{name} hà aghjuntu u vostru statutu à i so favuriti",
   "notification.follow": "{name} v'hà seguitatu",
   "notification.mention": "{name} v'hà mintuvatu",
@@ -295,6 +299,7 @@
   "poll.refresh": "Attualizà",
   "poll.total_votes": "{count, plural, one {# votu} other {# voti}}",
   "poll.vote": "Vutà",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Aghjunghje",
   "poll_button.remove_poll": "Toglie u scandagliu",
   "privacy.change": "Mudificà a cunfidenzialità di u statutu",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index 8acf27cb3..94a659435 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Odpovězením nyní přepíšete zprávu, kterou aktuálně píšete. Jste si jistý/á, že chcete pokračovat?",
   "confirmations.unfollow.confirm": "Přestat sledovat",
   "confirmations.unfollow.message": "jste si jistý/á, že chcete přestat sledovat uživatele {name}?",
+  "conversation.delete": "Smazat konverzaci",
+  "conversation.mark_as_read": "Označit jako přečtenou",
+  "conversation.open": "Zobrazit konverzaci",
+  "conversation.with": "S {names}",
   "directory.federated": "Ze známého fedivesmíru",
   "directory.local": "Pouze z {domain}",
   "directory.new_arrivals": "Nově příchozí",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Základní",
   "home.column_settings.show_reblogs": "Zobrazit boosty",
   "home.column_settings.show_replies": "Zobrazit odpovědi",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Aktualizovat v reálném čase",
   "intervals.full.days": "{number, plural, one {# den} few {# dny} many {# dne} other {# dní}}",
   "intervals.full.hours": "{number, plural, one {# hodina} few {# hodiny} many {# hodiny} other {# hodin}}",
   "intervals.full.minutes": "{number, plural, one {# minuta} few {# minuty} many {# minuty} other {# minut}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Předvolby",
   "navigation_bar.public_timeline": "Federovaná časová osa",
   "navigation_bar.security": "Zabezpečení",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "a {count, plural, one {# další} few {# další} many {# dalších} other {# dalších}}",
   "notification.favourite": "{name} si oblíbil/a váš toot",
   "notification.follow": "{name} vás začal/a sledovat",
   "notification.mention": "{name} vás zmínil/a",
@@ -295,6 +299,7 @@
   "poll.refresh": "Obnovit",
   "poll.total_votes": "{count, plural, one {# hlas} few {# hlasy} many {# hlasu} other {# hlasů}}",
   "poll.vote": "Hlasovat",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Přidat anketu",
   "poll_button.remove_poll": "Odstranit anketu",
   "privacy.change": "Změnit soukromí tootu",
diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json
index cdf2656d7..c7f679b22 100644
--- a/app/javascript/mastodon/locales/cy.json
+++ b/app/javascript/mastodon/locales/cy.json
@@ -4,7 +4,7 @@
   "account.block": "Blocio @{name}",
   "account.block_domain": "Cuddio popeth rhag {domain}",
   "account.blocked": "Blociwyd",
-  "account.cancel_follow_request": "Cancel follow request",
+  "account.cancel_follow_request": "Canslo cais dilyn",
   "account.direct": "Neges breifat @{name}",
   "account.domain_blocked": "Parth wedi ei guddio",
   "account.edit_profile": "Golygu proffil",
@@ -16,7 +16,7 @@
   "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.last_status": "Last active",
+  "account.last_status": "Gweithredol olaf",
   "account.link_verified_on": "Gwiriwyd perchnogaeth y ddolen yma ar {date}",
   "account.locked_info": "Mae'r statws preifatrwydd cyfrif hwn wedi'i osod i gloi. Mae'r perchennog yn adolygu'r sawl sy'n gallu eu dilyn.",
   "account.media": "Cyfryngau",
@@ -25,7 +25,7 @@
   "account.mute": "Tawelu @{name}",
   "account.mute_notifications": "Cuddio hysbysiadau o @{name}",
   "account.muted": "Distewyd",
-  "account.never_active": "Never",
+  "account.never_active": "Byth",
   "account.posts": "Tŵtiau",
   "account.posts_with_replies": "Tŵtiau ac atebion",
   "account.report": "Adrodd @{name}",
@@ -38,11 +38,11 @@
   "account.unfollow": "Dad-ddilyn",
   "account.unmute": "Dad-dawelu @{name}",
   "account.unmute_notifications": "Dad-dawelu hysbysiadau o @{name}",
-  "alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
-  "alert.rate_limited.title": "Rate limited",
+  "alert.rate_limited.message": "Ceisiwch eto ar ôl {retry_time, time, medium}.",
+  "alert.rate_limited.title": "Cyfradd gyfyngedig",
   "alert.unexpected.message": "Digwyddodd gwall annisgwyl.",
   "alert.unexpected.title": "Wps!",
-  "autosuggest_hashtag.per_week": "{count} per week",
+  "autosuggest_hashtag.per_week": "{count} yr wythnos",
   "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",
@@ -53,7 +53,7 @@
   "column.blocks": "Defnyddwyr a flociwyd",
   "column.community": "Ffrwd lleol",
   "column.direct": "Negeseuon preifat",
-  "column.directory": "Browse profiles",
+  "column.directory": "Pori proffiliau",
   "column.domain_blocks": "Parthau cuddiedig",
   "column.favourites": "Ffefrynnau",
   "column.follow_requests": "Ceisiadau dilyn",
@@ -63,7 +63,7 @@
   "column.notifications": "Hysbysiadau",
   "column.pins": "Tŵtiau wedi eu pinio",
   "column.public": "Ffrwd y ffederasiwn",
-  "column.status": "Toot",
+  "column.status": "Tŵt",
   "column_back_button.label": "Nôl",
   "column_header.hide_settings": "Cuddio dewisiadau",
   "column_header.moveLeft_settings": "Symud y golofn i'r chwith",
@@ -101,8 +101,8 @@
   "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 cynnwys o'r parth hwnnw mewn unrhyw ffrydiau cyhoeddus na chwaith yn eich hysbysiadau. Bydd hyn yn cael gwared o'ch dilynwyr o'r parth hwnnw.",
-  "confirmations.logout.confirm": "Log out",
-  "confirmations.logout.message": "Are you sure you want to log out?",
+  "confirmations.logout.confirm": "Allgofnodi",
+  "confirmations.logout.message": "Ydych chi'n siŵr eich bod am allgofnodi?",
   "confirmations.mute.confirm": "Tawelu",
   "confirmations.mute.message": "Ydych chi'n sicr eich bod am ddistewi {name}?",
   "confirmations.redraft.confirm": "Dileu & ailddrafftio",
@@ -111,10 +111,14 @@
   "confirmations.reply.message": "Bydd ateb nawr yn cymryd lle y neges yr ydych yn cyfansoddi ar hyn o bryd. Ydych chi'n sicr yr ydych am barhau?",
   "confirmations.unfollow.confirm": "Dad-ddilynwch",
   "confirmations.unfollow.message": "Ydych chi'n sicr eich bod am ddad-ddilyn {name}?",
-  "directory.federated": "From known fediverse",
-  "directory.local": "From {domain} only",
-  "directory.new_arrivals": "New arrivals",
-  "directory.recently_active": "Recently active",
+  "conversation.delete": "Dileu sgwrs",
+  "conversation.mark_as_read": "Nodi fel wedi'i ddarllen",
+  "conversation.open": "Gweld sgwrs",
+  "conversation.with": "Gyda {names}",
+  "directory.federated": "O ffedysawd hysbys",
+  "directory.local": "O {domain} yn unig",
+  "directory.new_arrivals": "Newydd-ddyfodiaid",
+  "directory.recently_active": "Yn weithredol yn ddiweddar",
   "embed.instructions": "Mewnblannwch y tŵt hwn ar eich gwefan drwy gopïo'r côd isod.",
   "embed.preview": "Dyma sut olwg fydd arno:",
   "emoji_button.activity": "Gweithgarwch",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Syml",
   "home.column_settings.show_reblogs": "Dangos bŵstiau",
   "home.column_settings.show_replies": "Dangos ymatebion",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Diweddariad mewn amser real",
   "intervals.full.days": "{number, plural, one {# ddydd} other {# o ddyddiau}}",
   "intervals.full.hours": "{number, plural, one {# awr} other {# o oriau}}",
   "intervals.full.minutes": "{number, plural, one {# funud} other {# o funudau}}",
@@ -236,7 +240,7 @@
   "lists.new.title_placeholder": "Teitl rhestr newydd",
   "lists.search": "Chwilio ymysg pobl yr ydych yn ei ddilyn",
   "lists.subheading": "Eich rhestrau",
-  "load_pending": "{count, plural, one {# new item} other {# new items}}",
+  "load_pending": "{count, plural, one {# eitem newydd} other {# eitemau newydd}}",
   "loading_indicator.label": "Llwytho...",
   "media_gallery.toggle_visible": "Toglo gwelededd",
   "missing_indicator.label": "Heb ei ganfod",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Dewisiadau",
   "navigation_bar.public_timeline": "Ffrwd y ffederasiwn",
   "navigation_bar.security": "Diogelwch",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "a {count, plural, one {# arall} other {# eraill}}",
   "notification.favourite": "hoffodd {name} eich tŵt",
   "notification.follow": "dilynodd {name} chi",
   "notification.mention": "Soniodd {name} amdanoch chi",
@@ -295,6 +299,7 @@
   "poll.refresh": "Adnewyddu",
   "poll.total_votes": "{count, plural, one {# bleidlais} other {# o bleidleisiau}}",
   "poll.vote": "Pleidleisio",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Ychwanegu pleidlais",
   "poll_button.remove_poll": "Tynnu pleidlais",
   "privacy.change": "Addasu preifatrwdd y tŵt",
@@ -330,7 +335,7 @@
   "search_results.accounts": "Pobl",
   "search_results.hashtags": "Hanshnodau",
   "search_results.statuses": "Tŵtiau",
-  "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
+  "search_results.statuses_fts_disabled": "Nid yw chwilio Tŵtiau yn ôl eu cynnwys wedi'i alluogi ar y gweinydd Mastodon hwn.",
   "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
   "status.admin_account": "Agor rhyngwyneb goruwchwylio ar gyfer @{name}",
   "status.admin_status": "Agor y tŵt yn y rhyngwyneb goruwchwylio",
@@ -369,7 +374,7 @@
   "status.show_more": "Dangos mwy",
   "status.show_more_all": "Dangos mwy i bawb",
   "status.show_thread": "Dangos edefyn",
-  "status.uncached_media_warning": "Not available",
+  "status.uncached_media_warning": "Dim ar gael",
   "status.unmute_conversation": "Dad-dawelu sgwrs",
   "status.unpin": "Dadbinio o'r proffil",
   "suggestions.dismiss": "Diswyddo",
@@ -385,22 +390,22 @@
   "time_remaining.moments": "Munudau ar ôl",
   "time_remaining.seconds": "{number, plural, one {# eiliad} other {# o eiliadau}} ar ôl",
   "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} yn siarad",
-  "trends.trending_now": "Trending now",
+  "trends.trending_now": "Yn tueddu nawr",
   "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_error.limit": "Wedi mynd heibio'r uchafswm terfyn uwchlwytho.",
   "upload_error.poll": "Nid oes modd uwchlwytho ffeiliau â phleidleisiau.",
   "upload_form.description": "Disgrifio i'r rheini a nam ar ei golwg",
-  "upload_form.edit": "Edit",
+  "upload_form.edit": "Golygu",
   "upload_form.undo": "Dileu",
-  "upload_modal.analyzing_picture": "Analyzing picture…",
-  "upload_modal.apply": "Apply",
-  "upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
-  "upload_modal.detect_text": "Detect text from picture",
-  "upload_modal.edit_media": "Edit media",
-  "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
-  "upload_modal.preview_label": "Preview ({ratio})",
+  "upload_modal.analyzing_picture": "Dadansoddi llun…",
+  "upload_modal.apply": "Gweithredu",
+  "upload_modal.description_placeholder": "Mae ei phen bach llawn jocs, 'run peth a fy nghot golff, rhai dyddiau",
+  "upload_modal.detect_text": "Canfod testun o'r llun",
+  "upload_modal.edit_media": "Golygu cyfryngau",
+  "upload_modal.hint": "Cliciwch neu llusgwch y cylch ar y rhagolwg i ddewis y canolbwynt a fydd bob amser i'w weld ar bob mân-lunau.",
+  "upload_modal.preview_label": "Rhagolwg ({ratio})",
   "upload_progress.label": "Uwchlwytho...",
   "video.close": "Cau fideo",
   "video.exit_fullscreen": "Gadael sgrîn llawn",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index 14b0f7563..852b6d157 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Hvis du svarer nu vil du overskrive den besked du er ved at skrive. Er du sikker på, du vil fortsætte?",
   "confirmations.unfollow.confirm": "Følg ikke længere",
   "confirmations.unfollow.message": "Er du sikker på, du ikke længere vil følge {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "Fra kendt fedivers",
   "directory.local": "Kun fra {domain}",
   "directory.new_arrivals": "Nye ankomster",
@@ -295,6 +299,7 @@
   "poll.refresh": "Opdatér",
   "poll.total_votes": "{count, plural, one {# stemme} other {# stemmer}}",
   "poll.vote": "Stem",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Tilføj en afstemning",
   "poll_button.remove_poll": "Fjern afstemning",
   "privacy.change": "Skift status visningsindstillinger",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index 845bc5156..08b75c9ec 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -63,7 +63,7 @@
   "column.notifications": "Mitteilungen",
   "column.pins": "Angeheftete Beiträge",
   "column.public": "Föderierte Zeitleiste",
-  "column.status": "Toot",
+  "column.status": "Beitrag",
   "column_back_button.label": "Zurück",
   "column_header.hide_settings": "Einstellungen verbergen",
   "column_header.moveLeft_settings": "Spalte nach links verschieben",
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Wenn du jetzt antwortest wird es die gesamte Nachricht verwerfen, die du gerade schreibst. Möchtest du wirklich fortfahren?",
   "confirmations.unfollow.confirm": "Entfolgen",
   "confirmations.unfollow.message": "Bist du dir sicher, dass du {name} entfolgen möchtest?",
+  "conversation.delete": "Unterhaltung löschen",
+  "conversation.mark_as_read": "Als gelesen markieren",
+  "conversation.open": "Unterhaltung anzeigen",
+  "conversation.with": "Mit {names}",
   "directory.federated": "Aus dem Fediverse",
   "directory.local": "Nur von {domain}",
   "directory.new_arrivals": "Neue Benutzer",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Einfach",
   "home.column_settings.show_reblogs": "Geteilte Beiträge anzeigen",
   "home.column_settings.show_replies": "Antworten anzeigen",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "In Echtzeit aktualisieren",
   "intervals.full.days": "{number, plural, one {# Tag} other {# Tage}}",
   "intervals.full.hours": "{number, plural, one {# Stunde} other {# Stunden}}",
   "intervals.full.minutes": "{number, plural, one {# Minute} other {# Minuten}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Einstellungen",
   "navigation_bar.public_timeline": "Föderierte Zeitleiste",
   "navigation_bar.security": "Sicherheit",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "und {count, plural, one {# andere Person} other {# andere Personen}}",
   "notification.favourite": "{name} hat deinen Beitrag favorisiert",
   "notification.follow": "{name} folgt dir",
   "notification.mention": "{name} hat dich erwähnt",
@@ -295,6 +299,7 @@
   "poll.refresh": "Aktualisieren",
   "poll.total_votes": "{count, plural, one {# Stimme} other {# Stimmen}}",
   "poll.vote": "Abstimmen",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Eine Umfrage erstellen",
   "poll_button.remove_poll": "Umfrage entfernen",
   "privacy.change": "Sichtbarkeit des Beitrags anpassen",
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index 0d682c983..efefafe55 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -234,6 +234,11 @@
         "id": "poll.closed"
       },
       {
+        "defaultMessage": "You voted for this answer",
+        "description": "Tooltip of the \"voted\" checkmark in polls",
+        "id": "poll.voted"
+      },
+      {
         "defaultMessage": "Vote",
         "id": "poll.vote"
       },
@@ -1267,6 +1272,56 @@
   {
     "descriptors": [
       {
+        "defaultMessage": "More",
+        "id": "status.more"
+      },
+      {
+        "defaultMessage": "View conversation",
+        "id": "conversation.open"
+      },
+      {
+        "defaultMessage": "Reply",
+        "id": "status.reply"
+      },
+      {
+        "defaultMessage": "Mark as read",
+        "id": "conversation.mark_as_read"
+      },
+      {
+        "defaultMessage": "Delete conversation",
+        "id": "conversation.delete"
+      },
+      {
+        "defaultMessage": "Mute conversation",
+        "id": "status.mute_conversation"
+      },
+      {
+        "defaultMessage": "Unmute conversation",
+        "id": "status.unmute_conversation"
+      },
+      {
+        "defaultMessage": "With {names}",
+        "id": "conversation.with"
+      }
+    ],
+    "path": "app/javascript/mastodon/features/direct_timeline/components/conversation.json"
+  },
+  {
+    "descriptors": [
+      {
+        "defaultMessage": "Reply",
+        "id": "confirmations.reply.confirm"
+      },
+      {
+        "defaultMessage": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
+        "id": "confirmations.reply.message"
+      }
+    ],
+    "path": "app/javascript/mastodon/features/direct_timeline/containers/conversation_container.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 bdd1da36c..9425c3f12 100644
--- a/app/javascript/mastodon/locales/el.json
+++ b/app/javascript/mastodon/locales/el.json
@@ -1,7 +1,7 @@
 {
   "account.add_or_remove_from_list": "Προσθήκη ή Αφαίρεση από λίστες",
   "account.badges.bot": "Μποτ",
-  "account.block": "Αποκλισμός @{name}",
+  "account.block": "Αποκλεισμός @{name}",
   "account.block_domain": "Απόκρυψε τα πάντα από το {domain}",
   "account.blocked": "Αποκλεισμένος/η",
   "account.cancel_follow_request": "Ακύρωση αιτήματος παρακολούθησης",
@@ -63,7 +63,7 @@
   "column.notifications": "Ειδοποιήσεις",
   "column.pins": "Καρφιτσωμένα τουτ",
   "column.public": "Ομοσπονδιακή ροή",
-  "column.status": "Toot",
+  "column.status": "Τουτ",
   "column_back_button.label": "Πίσω",
   "column_header.hide_settings": "Απόκρυψη ρυθμίσεων",
   "column_header.moveLeft_settings": "Μεταφορά κολώνας αριστερά",
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Απαντώντας τώρα θα αντικαταστήσεις το κείμενο που ήδη γράφεις. Σίγουρα θέλεις να συνεχίσεις;",
   "confirmations.unfollow.confirm": "Διακοπή παρακολούθησης",
   "confirmations.unfollow.message": "Σίγουρα θες να πάψεις να ακολουθείς τον/την {name};",
+  "conversation.delete": "Διαγραφή συζήτησης",
+  "conversation.mark_as_read": "Σήμανση ως αναγνωσμένο",
+  "conversation.open": "Προβολή συνομιλίας",
+  "conversation.with": "Με {names}",
   "directory.federated": "Από το γνωστό fediverse",
   "directory.local": "Μόνο από {domain}",
   "directory.new_arrivals": "Νέες αφίξεις",
@@ -127,7 +131,7 @@
   "emoji_button.objects": "Αντικείμενα",
   "emoji_button.people": "Άνθρωποι",
   "emoji_button.recent": "Δημοφιλή",
-  "emoji_button.search": "Αναζήτηση…",
+  "emoji_button.search": "Αναζήτηση...",
   "emoji_button.search_results": "Αποτελέσματα αναζήτησης",
   "emoji_button.symbols": "Σύμβολα",
   "emoji_button.travel": "Ταξίδια & Τοποθεσίες",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Βασικές ρυθμίσεις",
   "home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
   "home.column_settings.show_replies": "Εμφάνιση απαντήσεων",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Ενημέρωση σε πραγματικό χρόνο",
   "intervals.full.days": "{number, plural, one {# μέρα} other {# μέρες}}",
   "intervals.full.hours": "{number, plural, one {# ώρα} other {# ώρες}}",
   "intervals.full.minutes": "{number, plural, one {# λεπτό} other {# λεπτά}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Προτιμήσεις",
   "navigation_bar.public_timeline": "Ομοσπονδιακή ροή",
   "navigation_bar.security": "Ασφάλεια",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "και {count, plural, one {# άλλη} other {# άλλες}}",
   "notification.favourite": "Ο/Η {name} σημείωσε ως αγαπημένη την κατάστασή σου",
   "notification.follow": "Ο/Η {name} σε ακολούθησε",
   "notification.mention": "Ο/Η {name} σε ανέφερε",
@@ -295,6 +299,7 @@
   "poll.refresh": "Ανανέωση",
   "poll.total_votes": "{count, plural, one {# ψήφος} other {# ψήφοι}}",
   "poll.vote": "Ψήφισε",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Προσθήκη δημοσκόπησης",
   "poll_button.remove_poll": "Αφαίρεση δημοσκόπησης",
   "privacy.change": "Προσαρμογή ιδιωτικότητας δημοσίευσης",
@@ -388,7 +393,7 @@
   "trends.trending_now": "Δημοφιλή τώρα",
   "ui.beforeunload": "Το προσχέδιό σου θα χαθεί αν φύγεις από το Mastodon.",
   "upload_area.title": "Drag & drop για να ανεβάσεις",
-  "upload_button.label": "Πρόσθεσε πολυμέσα (JPEG, PNG, GIF, WebM, MP4, MOV)",
+  "upload_button.label": "Πρόσθεσε πολυμέσα ({formats})",
   "upload_error.limit": "Υπέρβαση ορίου μεγέθους ανεβασμένων αρχείων.",
   "upload_error.poll": "Στις δημοσκοπήσεις δεν επιτρέπεται η μεταφόρτωση αρχείου.",
   "upload_form.description": "Περιέγραψε για όσους & όσες έχουν προβλήματα όρασης",
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 15c579d51..27121d121 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -115,6 +115,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -300,6 +304,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index 31750050e..bf08a08fb 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -4,7 +4,7 @@
   "account.block": "Bloki @{name}",
   "account.block_domain": "Kaŝi ĉion de {domain}",
   "account.blocked": "Blokita",
-  "account.cancel_follow_request": "Nuligi peto de sekvado",
+  "account.cancel_follow_request": "Nuligi peton de sekvado",
   "account.direct": "Rekte mesaĝi @{name}",
   "account.domain_blocked": "Domajno kaŝita",
   "account.edit_profile": "Redakti profilon",
@@ -16,14 +16,14 @@
   "account.follows.empty": "Tiu uzanto ankoraŭ ne sekvas iun.",
   "account.follows_you": "Sekvas vin",
   "account.hide_reblogs": "Kaŝi diskonigojn de @{name}",
-  "account.last_status": "Lasta aktiva",
+  "account.last_status": "Laste aktiva",
   "account.link_verified_on": "La posedanto de tiu ligilo estis kontrolita je {date}",
   "account.locked_info": "La privateco de tiu konto estas elektita kiel fermita. La posedanto povas mane akcepti tiun, kiu povas sekvi rin.",
   "account.media": "Aŭdovidaĵoj",
   "account.mention": "Mencii @{name}",
   "account.moved_to": "{name} moviĝis al:",
   "account.mute": "Silentigi @{name}",
-  "account.mute_notifications": "Silentigi sciigojn el @{name}",
+  "account.mute_notifications": "Silentigi sciigojn de @{name}",
   "account.muted": "Silentigita",
   "account.never_active": "Neniam",
   "account.posts": "Mesaĝoj",
@@ -38,8 +38,8 @@
   "account.unfollow": "Ne plu sekvi",
   "account.unmute": "Malsilentigi @{name}",
   "account.unmute_notifications": "Malsilentigi sciigojn de @{name}",
-  "alert.rate_limited.message": "Bonvolu reprovi poste {retry_time, time, medium}.",
-  "alert.rate_limited.title": "Rate limited",
+  "alert.rate_limited.message": "Bonvolu reprovi post {retry_time, time, medium}.",
+  "alert.rate_limited.title": "Mesaĝkvante limigita",
   "alert.unexpected.message": "Neatendita eraro okazis.",
   "alert.unexpected.title": "Ups!",
   "autosuggest_hashtag.per_week": "{count} semajne",
@@ -53,7 +53,7 @@
   "column.blocks": "Blokitaj uzantoj",
   "column.community": "Loka tempolinio",
   "column.direct": "Rektaj mesaĝoj",
-  "column.directory": "Browse profiles",
+  "column.directory": "Trarigardi profilojn",
   "column.domain_blocks": "Kaŝitaj domajnoj",
   "column.favourites": "Stelumoj",
   "column.follow_requests": "Petoj de sekvado",
@@ -63,7 +63,7 @@
   "column.notifications": "Sciigoj",
   "column.pins": "Alpinglitaj mesaĝoj",
   "column.public": "Fratara tempolinio",
-  "column.status": "Toot",
+  "column.status": "Mesaĝo",
   "column_back_button.label": "Reveni",
   "column_header.hide_settings": "Kaŝi agordojn",
   "column_header.moveLeft_settings": "Movi kolumnon maldekstren",
@@ -79,10 +79,10 @@
   "compose_form.lock_disclaimer": "Via konta ne estas {locked}. Iu ajn povas sekvi vin por vidi viajn mesaĝojn, kiuj estas nur por sekvantoj.",
   "compose_form.lock_disclaimer.lock": "ŝlosita",
   "compose_form.placeholder": "Pri kio vi pensas?",
-  "compose_form.poll.add_option": "Aldoni elekto",
+  "compose_form.poll.add_option": "Aldoni elekteblon",
   "compose_form.poll.duration": "Balotenketa daŭro",
-  "compose_form.poll.option_placeholder": "elekto {number}",
-  "compose_form.poll.remove_option": "Forigi ĉi tiu elekton",
+  "compose_form.poll.option_placeholder": "Elekteblo {number}",
+  "compose_form.poll.remove_option": "Forigi ĉi tiu elekteblon",
   "compose_form.publish": "Hup",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.hide": "Marki la aŭdovidaĵojn kiel tiklaj",
@@ -92,7 +92,7 @@
   "compose_form.spoiler.unmarked": "Teksto ne kaŝita",
   "compose_form.spoiler_placeholder": "Skribu vian averton ĉi tie",
   "confirmation_modal.cancel": "Nuligi",
-  "confirmations.block.block_and_report": "Bloki & Signali",
+  "confirmations.block.block_and_report": "Bloki kaj signali",
   "confirmations.block.confirm": "Bloki",
   "confirmations.block.message": "Ĉu vi certas, ke vi volas bloki {name}?",
   "confirmations.delete.confirm": "Forigi",
@@ -111,10 +111,14 @@
   "confirmations.reply.message": "Respondi nun anstataŭigos la mesaĝon, kiun vi nun skribas. Ĉu vi certas, ke vi volas daŭrigi?",
   "confirmations.unfollow.confirm": "Ne plu sekvi",
   "confirmations.unfollow.message": "Ĉu vi certas, ke vi volas ĉesi sekvi {name}?",
+  "conversation.delete": "Forigi konversacion",
+  "conversation.mark_as_read": "Marki legita",
+  "conversation.open": "Vidi konversacion",
+  "conversation.with": "Kun {names}",
   "directory.federated": "El konata fediverso",
   "directory.local": "Nur de {domain}",
-  "directory.new_arrivals": "Novaj veniĝoj",
-  "directory.recently_active": "Recently active",
+  "directory.new_arrivals": "Novaj alvenoj",
+  "directory.recently_active": "Lastatempe aktiva",
   "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",
@@ -166,18 +170,18 @@
   "hashtag.column_settings.tag_mode.all": "Ĉiuj",
   "hashtag.column_settings.tag_mode.any": "Iu ajn",
   "hashtag.column_settings.tag_mode.none": "Neniu",
-  "hashtag.column_settings.tag_toggle": "Inkluzivi pluajn etikedojn por ĉi tiu kolumno",
+  "hashtag.column_settings.tag_toggle": "Aldoni pliajn etikedojn por ĉi tiu kolumno",
   "home.column_settings.basic": "Bazaj agordoj",
   "home.column_settings.show_reblogs": "Montri diskonigojn",
   "home.column_settings.show_replies": "Montri respondojn",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Tuje ĝisdatigi",
   "intervals.full.days": "{number, plural, one {# tago} other {# tagoj}}",
   "intervals.full.hours": "{number, plural, one {# horo} other {# horoj}}",
   "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutoj}}",
   "introduction.federation.action": "Sekva",
-  "introduction.federation.federated.headline": "Federacio",
+  "introduction.federation.federated.headline": "Fratara",
   "introduction.federation.federated.text": "Publikaj mesaĝoj el aliaj serviloj de la Fediverse aperos en la fratara tempolinio.",
-  "introduction.federation.home.headline": "Heimo",
+  "introduction.federation.home.headline": "Hejmo",
   "introduction.federation.home.text": "Mesaĝoj de homoj, kiujn vi sekvas, aperos en via hejma fluo. Vi povas sekvi iun ajn de ajna servilo!",
   "introduction.federation.local.headline": "Loka",
   "introduction.federation.local.text": "Publikaj mesaĝoj de homoj de via servilo aperos en la loka tempolinio.",
@@ -226,7 +230,7 @@
   "lightbox.close": "Fermi",
   "lightbox.next": "Sekva",
   "lightbox.previous": "Antaŭa",
-  "lightbox.view_context": "Vidi kontekston",
+  "lightbox.view_context": "Vidi kuntekston",
   "lists.account.add": "Aldoni al la listo",
   "lists.account.remove": "Forigi de la listo",
   "lists.delete": "Forigi la liston",
@@ -236,12 +240,12 @@
   "lists.new.title_placeholder": "Titolo de la nova listo",
   "lists.search": "Serĉi inter la homoj, kiujn vi sekvas",
   "lists.subheading": "Viaj listoj",
-  "load_pending": "{count,plural, one {# nova ero} other {# novaj eroj}}",
+  "load_pending": "{count,plural, one {# nova elemento} other {# novaj elementoj}}",
   "loading_indicator.label": "Ŝargado…",
   "media_gallery.toggle_visible": "Baskuligi videblecon",
   "missing_indicator.label": "Ne trovita",
   "missing_indicator.sublabel": "Ĉi tiu elemento ne estis trovita",
-  "mute_modal.hide_notifications": "Ĉu vi volas kaŝi la sciigojn el ĉi tiu uzanto?",
+  "mute_modal.hide_notifications": "Ĉu vi volas kaŝi la sciigojn de ĉi tiu uzanto?",
   "navigation_bar.apps": "Telefonaj aplikaĵoj",
   "navigation_bar.blocks": "Blokitaj uzantoj",
   "navigation_bar.community_timeline": "Loka tempolinio",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Preferoj",
   "navigation_bar.public_timeline": "Fratara tempolinio",
   "navigation_bar.security": "Sekureco",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "kaj {count, plural, one {# alia} other {# aliaj}}",
   "notification.favourite": "{name} stelumis vian mesaĝon",
   "notification.follow": "{name} eksekvis vin",
   "notification.mention": "{name} menciis vin",
@@ -295,6 +299,7 @@
   "poll.refresh": "Aktualigi",
   "poll.total_votes": "{count, plural, one {# voĉdono} other {# voĉdonoj}}",
   "poll.vote": "Voĉdoni",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Aldoni balotenketon",
   "poll_button.remove_poll": "Forigi balotenketon",
   "privacy.change": "Agordi mesaĝan privatecon",
@@ -335,7 +340,7 @@
   "status.admin_account": "Malfermi la kontrolan interfacon por @{name}",
   "status.admin_status": "Malfermi ĉi tiun mesaĝon en la kontrola interfaco",
   "status.block": "Bloki @{name}",
-  "status.cancel_reblog_private": "Eksdiskonigi",
+  "status.cancel_reblog_private": "Ne plu diskonigi",
   "status.cannot_reblog": "Ĉi tiu mesaĝo ne diskonigeblas",
   "status.copy": "Kopii la ligilon al la mesaĝo",
   "status.delete": "Forigi",
@@ -394,19 +399,19 @@
   "upload_form.description": "Priskribi por misvidantaj homoj",
   "upload_form.edit": "Redakti",
   "upload_form.undo": "Forigi",
-  "upload_modal.analyzing_picture": "Analyzing picture…",
+  "upload_modal.analyzing_picture": "Bilda analizado…",
   "upload_modal.apply": "Apliki",
-  "upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
-  "upload_modal.detect_text": "Detect text from picture",
-  "upload_modal.edit_media": "Redakti aŭdvidaĵo",
-  "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
+  "upload_modal.description_placeholder": "Laŭ Ludoviko Zamenhof bongustas freŝa ĉeĥa manĝaĵo kun spicoj",
+  "upload_modal.detect_text": "Detekti tekston de la bildo",
+  "upload_modal.edit_media": "Redakti aŭdovidaĵon",
+  "upload_modal.hint": "Klaku aŭ trenu la cirklon en la antaŭvidilo por elekti la fokuspunkton kiu ĉiam videblos en ĉiuj etigitaj bildoj.",
   "upload_modal.preview_label": "Antaŭvido ({ratio})",
   "upload_progress.label": "Alŝutado…",
-  "video.close": "Fermi videon",
+  "video.close": "Fermi la videon",
   "video.exit_fullscreen": "Eksigi plenekrana",
-  "video.expand": "Grandigi videon",
+  "video.expand": "Grandigi la videon",
   "video.fullscreen": "Igi plenekrana",
-  "video.hide": "Kaŝi videon",
+  "video.hide": "Kaŝi la videon",
   "video.mute": "Silentigi",
   "video.pause": "Paŭzi",
   "video.play": "Ekigi",
diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json
new file mode 100644
index 000000000..89ddcbf51
--- /dev/null
+++ b/app/javascript/mastodon/locales/es-AR.json
@@ -0,0 +1,419 @@
+{
+  "account.add_or_remove_from_list": "Agregar o quitar de las listas",
+  "account.badges.bot": "Bot",
+  "account.block": "Bloquear a @{name}",
+  "account.block_domain": "Ocultar todo de {domain}",
+  "account.blocked": "Bloqueado",
+  "account.cancel_follow_request": "Cancelar la solicitud de seguimiento",
+  "account.direct": "Mensaje directo a @{name}",
+  "account.domain_blocked": "Dominio oculto",
+  "account.edit_profile": "Editar perfil",
+  "account.endorse": "Destacar en el perfil",
+  "account.follow": "Seguir",
+  "account.followers": "Seguidores",
+  "account.followers.empty": "Todavía nadie sigue a este usuario.",
+  "account.follows": "Sigue",
+  "account.follows.empty": "Todavía este usuario no sigue a nadie.",
+  "account.follows_you": "Te sigue",
+  "account.hide_reblogs": "Ocultar retoots de @{name}",
+  "account.last_status": "Última actividad",
+  "account.link_verified_on": "La propiedad de este enlace fue verificada el {date}",
+  "account.locked_info": "El estado de privacidad de esta cuenta está establecido como bloqueado. El propietario manualmente revisa quién puede seguirle.",
+  "account.media": "Medios",
+  "account.mention": "Mencionar a @{name}",
+  "account.moved_to": "{name} se ha muó a:",
+  "account.mute": "Silenciar a @{name}",
+  "account.mute_notifications": "Silenciar notificaciones de @{name}",
+  "account.muted": "Silenciado",
+  "account.never_active": "Nunca",
+  "account.posts": "Toots",
+  "account.posts_with_replies": "Toots con respuestas",
+  "account.report": "Denunciar a @{name}",
+  "account.requested": "Esperando aprobación. Hacé clic para cancelar la solicitud de seguimiento.",
+  "account.share": "Compartir el perfil de @{name}",
+  "account.show_reblogs": "Mostrar retoots de @{name}",
+  "account.unblock": "Desbloquear a @{name}",
+  "account.unblock_domain": "Mostrar {domain}",
+  "account.unendorse": "No destacar en el perfil",
+  "account.unfollow": "Dejar de seguir",
+  "account.unmute": "Dejar de silenciar a @{name}",
+  "account.unmute_notifications": "Dejar de silenciar las notificaciones de @{name}",
+  "alert.rate_limited.message": "Por favor, reintentá después de las {retry_time, time, medium}.",
+  "alert.rate_limited.title": "Tarifa limitada",
+  "alert.unexpected.message": "Ocurrió un error inesperado.",
+  "alert.unexpected.title": "¡Epa!",
+  "autosuggest_hashtag.per_week": "{count} por semana",
+  "boost_modal.combo": "Podés hacer clic en {combo} para saltar esto la próxima vez",
+  "bundle_column_error.body": "Algo salió mal al cargar este componente.",
+  "bundle_column_error.retry": "Intentá de nuevo",
+  "bundle_column_error.title": "Error de red",
+  "bundle_modal_error.close": "Cerrar",
+  "bundle_modal_error.message": "Algo salió mal al cargar este componente.",
+  "bundle_modal_error.retry": "Intentá de nuevo",
+  "column.blocks": "Usuarios bloqueados",
+  "column.community": "Línea temporal local",
+  "column.direct": "Mensajes directos",
+  "column.directory": "Explorar perfiles",
+  "column.domain_blocks": "Dominios ocultos",
+  "column.favourites": "Favoritos",
+  "column.follow_requests": "Solicitudes de seguimiento",
+  "column.home": "Principal",
+  "column.lists": "Listas",
+  "column.mutes": "Usuarios silenciados",
+  "column.notifications": "Notificaciones",
+  "column.pins": "Toots fijados",
+  "column.public": "Línea temporal federada",
+  "column.status": "Toot",
+  "column_back_button.label": "Volver",
+  "column_header.hide_settings": "Ocultar configuración",
+  "column_header.moveLeft_settings": "Mover columna a la izquierda",
+  "column_header.moveRight_settings": "Mover columna a la derecha",
+  "column_header.pin": "Fijar",
+  "column_header.show_settings": "Mostrar configuración",
+  "column_header.unpin": "Dejar de fijar",
+  "column_subheading.settings": "Configuración",
+  "community.column_settings.media_only": "Sólo medios",
+  "compose_form.direct_message_warning": "Este toot sólo será enviado a los usuarios mencionados.",
+  "compose_form.direct_message_warning_learn_more": "Aprendé más",
+  "compose_form.hashtag_warning": "Este toot no se mostrará bajo hashtags porque no es público. Sólo los toots públicos se pueden buscar por hashtag.",
+  "compose_form.lock_disclaimer": "Tu cuenta no está {locked}. Todos pueden seguirte para ver tus toots marcados como \"sólo para seguidores\".",
+  "compose_form.lock_disclaimer.lock": "bloqueada",
+  "compose_form.placeholder": "¿Qué onda?",
+  "compose_form.poll.add_option": "Agregá una opción",
+  "compose_form.poll.duration": "Duración de la encuesta",
+  "compose_form.poll.option_placeholder": "Opción {number}",
+  "compose_form.poll.remove_option": "Quitá esta opción",
+  "compose_form.publish": "Tootear",
+  "compose_form.publish_loud": "¡{publish}!",
+  "compose_form.sensitive.hide": "Marcar medio como sensible",
+  "compose_form.sensitive.marked": "El medio se marcó como sensible",
+  "compose_form.sensitive.unmarked": "El medio no está marcado como sensible",
+  "compose_form.spoiler.marked": "El texto está oculto detrás de la advertencia",
+  "compose_form.spoiler.unmarked": "El texto no está oculto",
+  "compose_form.spoiler_placeholder": "Escribí tu advertencia acá",
+  "confirmation_modal.cancel": "Cancelar",
+  "confirmations.block.block_and_report": "Bloquear y denunciar",
+  "confirmations.block.confirm": "Bloquear",
+  "confirmations.block.message": "¿Estás seguro que querés bloquear a {name}?",
+  "confirmations.delete.confirm": "Eliminar",
+  "confirmations.delete.message": "¿Estás seguro que querés eliminar este estado?",
+  "confirmations.delete_list.confirm": "Eliminar",
+  "confirmations.delete_list.message": "¿Estás seguro que querés eliminar permanentemente esta lista?",
+  "confirmations.domain_block.confirm": "Ocultar dominio entero",
+  "confirmations.domain_block.message": "¿Estás completamente seguro que querés bloquear el {domain} entero? En la mayoría de los casos, unos cuantos bloqueos y silenciados puntuales son suficientes y preferibles. No vas a ver contenido de ese dominio en ninguna de tus líneas temporales o en tus notificaciones. Tus seguidores de ese dominio serán quitados.",
+  "confirmations.logout.confirm": "Cerrar sesión",
+  "confirmations.logout.message": "¿Estás seguro que querés cerrar la sesión?",
+  "confirmations.mute.confirm": "Silenciar",
+  "confirmations.mute.message": "¿Estás seguro que querés silenciar a {name}?",
+  "confirmations.redraft.confirm": "Eliminar toot original y editarlo",
+  "confirmations.redraft.message": "¿Estás seguro que querés eliminar este estado y volverlo a editarlo? Se perderán las veces marcadas como favoritos y los retoots, y las respuestas a la publicación original quedarán huérfanas.",
+  "confirmations.reply.confirm": "Responder",
+  "confirmations.reply.message": "Responder ahora sobreescribirá el mensaje que estás redactando actualmente. ¿Estás seguro que querés seguir?",
+  "confirmations.unfollow.confirm": "Dejar de seguir",
+  "confirmations.unfollow.message": "¿Estás seguro que querés dejar de seguir a {name}?",
+  "conversation.delete": "Eliminar conversación",
+  "conversation.mark_as_read": "Marcar como leído",
+  "conversation.open": "Ver conversación",
+  "conversation.with": "Con {names}",
+  "directory.federated": "Desde fediverso conocido",
+  "directory.local": "Sólo de {domain}",
+  "directory.new_arrivals": "Recién llegados",
+  "directory.recently_active": "Recientemente activo",
+  "embed.instructions": "Insertá este toot a tu sitio web copiando el código de abajo.",
+  "embed.preview": "Así es cómo se verá:",
+  "emoji_button.activity": "Actividad",
+  "emoji_button.custom": "Personalizado",
+  "emoji_button.flags": "Banderas",
+  "emoji_button.food": "Comida y bebida",
+  "emoji_button.label": "Insertar emoji",
+  "emoji_button.nature": "Naturaleza",
+  "emoji_button.not_found": "¡¡No emojos!! (╯°□°)╯︵ ┻━┻",
+  "emoji_button.objects": "Objetos",
+  "emoji_button.people": "Gente",
+  "emoji_button.recent": "Usados frecuentemente",
+  "emoji_button.search": "Buscar…",
+  "emoji_button.search_results": "Resultados de búsqueda",
+  "emoji_button.symbols": "Símbolos",
+  "emoji_button.travel": "Viajes y lugares",
+  "empty_column.account_timeline": "¡No hay toots aquí!",
+  "empty_column.account_unavailable": "Perfil no disponible",
+  "empty_column.blocks": "Todavía no bloqueaste a ningún usuario.",
+  "empty_column.community": "La línea temporal local está vacía. ¡Escribí algo en modo público para que se empiece a correr la bola!",
+  "empty_column.direct": "Todavía no tenés ningún mensaje directo. Cuando enviés o recibás uno, se mostrará acá.",
+  "empty_column.domain_blocks": "Todavía no hay dominios ocultos.",
+  "empty_column.favourited_statuses": "Todavía no tenés toots favoritos. Cuando marqués uno como favorito, se mostrará acá.",
+  "empty_column.favourites": "Todavía nadie marcó este toot como favorito. Cuando alguien lo haga, se mostrará acá.",
+  "empty_column.follow_requests": "Todavía no tenés ninguna solicitud de seguimiento. Cuando recibás una, se mostrará acá.",
+  "empty_column.hashtag": "Todavía no hay nada con esta etiqueta.",
+  "empty_column.home": "¡Tu línea temporal principal está vacía! Visitá {public} o usá la búsqueda para comenzar y encontrar a otros usuarios.",
+  "empty_column.home.public_timeline": "la línea temporal pública",
+  "empty_column.list": "Todavía no hay nada en esta lista. Cuando miembros de esta lista envíen nuevos toots, se mostrarán acá.",
+  "empty_column.lists": "Todavía no tienes ninguna lista. Cuando creés una, se mostrará acá.",
+  "empty_column.mutes": "Todavía no silenciaste a ningún usuario.",
+  "empty_column.notifications": "Todavía no tenés ninguna notificación. Interactuá con otros para iniciar la conversación.",
+  "empty_column.public": "¡Naranja! Escribí algo públicamente, o seguí usuarios manualmente de otros servidores para ir llenando esta línea temporal.",
+  "follow_request.authorize": "Autorizar",
+  "follow_request.reject": "Rechazar",
+  "getting_started.developers": "Desarrolladores",
+  "getting_started.directory": "Directorio de perfiles",
+  "getting_started.documentation": "Documentación",
+  "getting_started.heading": "Introducción",
+  "getting_started.invite": "Invitar usuarios",
+  "getting_started.open_source_notice": "Mastodon es software libre. Podés contribuir o informar errores en {github}.",
+  "getting_started.security": "Seguridad",
+  "getting_started.terms": "Términos del servicio",
+  "hashtag.column_header.tag_mode.all": "y {additional}",
+  "hashtag.column_header.tag_mode.any": "o {additional}",
+  "hashtag.column_header.tag_mode.none": "sin {additional}",
+  "hashtag.column_settings.select.no_options_message": "No se encontraron sugerencias",
+  "hashtag.column_settings.select.placeholder": "Introducí etiquetas…",
+  "hashtag.column_settings.tag_mode.all": "Todas estas",
+  "hashtag.column_settings.tag_mode.any": "Cualquiera de estas",
+  "hashtag.column_settings.tag_mode.none": "Ninguna de estas",
+  "hashtag.column_settings.tag_toggle": "Incluir etiquetas adicionales para esta columna",
+  "home.column_settings.basic": "Básico",
+  "home.column_settings.show_reblogs": "Mostrar retoots",
+  "home.column_settings.show_replies": "Mostrar respuestas",
+  "home.column_settings.update_live": "Actualizar en tiempo real",
+  "intervals.full.days": "{number, plural, one {# día} other {# días}}",
+  "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
+  "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
+  "introduction.federation.action": "Siguiente",
+  "introduction.federation.federated.headline": "Federado",
+  "introduction.federation.federated.text": "Los toots públicos de otros servidores del fediverso aparecerán en la línea temporal federada.",
+  "introduction.federation.home.headline": "Principal",
+  "introduction.federation.home.text": "Los toots de las personas que seguíss aparecerán en tu línea temporal principal. ¡Podés seguir a cualquiera en cualquier servidor!",
+  "introduction.federation.local.headline": "Local",
+  "introduction.federation.local.text": "Los toots públicos de las personas en el mismo servidor aparecerán en la línea temporal local.",
+  "introduction.interactions.action": "¡Terminar tutorial!",
+  "introduction.interactions.favourite.headline": "Favorito",
+  "introduction.interactions.favourite.text": "Podés guardar un toot para más tarde, y hacerle saber al autor que te gustó, marcándolo como favorito.",
+  "introduction.interactions.reblog.headline": "Retootear",
+  "introduction.interactions.reblog.text": "Podés compartir los toots de otras personas con tus seguidores retooteando los mismos.",
+  "introduction.interactions.reply.headline": "Responder",
+  "introduction.interactions.reply.text": "Podés responder a tus propios toots y los de otras personas, que se encadenarán juntos en una conversación.",
+  "introduction.welcome.action": "¡Dale!",
+  "introduction.welcome.headline": "Primeros pasos",
+  "introduction.welcome.text": "¡Bienvenido al fediverso! En unos pocos minutos, vas a poder transmitir mensajes y hablar con tus amigos a través de una amplia variedad de servidores. Pero este servidor, {domain}, es especial: aloja tu perfil, así que acordate de su nombre.",
+  "keyboard_shortcuts.back": "para volver",
+  "keyboard_shortcuts.blocked": "para abrir la lista de usuarios bloqueados",
+  "keyboard_shortcuts.boost": "para retootear",
+  "keyboard_shortcuts.column": "para enfocar un estado en una de las columnas",
+  "keyboard_shortcuts.compose": "para enfocar el área de texto de redacción",
+  "keyboard_shortcuts.description": "Descripción",
+  "keyboard_shortcuts.direct": "para abrir columna de mensajes directos",
+  "keyboard_shortcuts.down": "para bajar en la lista",
+  "keyboard_shortcuts.enter": "para abrir el estado",
+  "keyboard_shortcuts.favourite": "para marcar como favorito",
+  "keyboard_shortcuts.favourites": "para abrir la lista de favoritos",
+  "keyboard_shortcuts.federated": "para abrir la línea temporal federada",
+  "keyboard_shortcuts.heading": "Atajos de teclado",
+  "keyboard_shortcuts.home": "para abrir la línea temporal principal",
+  "keyboard_shortcuts.hotkey": "Combinación",
+  "keyboard_shortcuts.legend": "para mostrar este texto",
+  "keyboard_shortcuts.local": "para abrir la línea temporal local",
+  "keyboard_shortcuts.mention": "para mencionar al autor",
+  "keyboard_shortcuts.muted": "abrir la lista de usuarios silenciados",
+  "keyboard_shortcuts.my_profile": "para abrir tu perfil",
+  "keyboard_shortcuts.notifications": "para abrir la columna de notificaciones",
+  "keyboard_shortcuts.pinned": "para abrir lista de toots fijados",
+  "keyboard_shortcuts.profile": "para abrir el perfil del autor",
+  "keyboard_shortcuts.reply": "para responder",
+  "keyboard_shortcuts.requests": "para abrir la lista de solicitudes de seguimiento",
+  "keyboard_shortcuts.search": "para enfocar la búsqueda",
+  "keyboard_shortcuts.start": "para abrir la columna \"Introducción\"",
+  "keyboard_shortcuts.toggle_hidden": "para mostrar/ocultar el texto detrás de la advertencia de contenido",
+  "keyboard_shortcuts.toggle_sensitivity": "para mostrar/ocultar los medios",
+  "keyboard_shortcuts.toot": "para comenzar un toot nuevo",
+  "keyboard_shortcuts.unfocus": "para quitar el enfoque del área de texto de redacción o de búsqueda",
+  "keyboard_shortcuts.up": "para subir en la lista",
+  "lightbox.close": "Cerrar",
+  "lightbox.next": "Siguiente",
+  "lightbox.previous": "Anterior",
+  "lightbox.view_context": "Ver contexto",
+  "lists.account.add": "Agregar a lista",
+  "lists.account.remove": "Quitar de lista",
+  "lists.delete": "Eliminar lista",
+  "lists.edit": "Editar lista",
+  "lists.edit.submit": "Cambiar título",
+  "lists.new.create": "Agregar lista",
+  "lists.new.title_placeholder": "Nuevo título de lista",
+  "lists.search": "Buscar entre la gente que seguís",
+  "lists.subheading": "Tus listas",
+  "load_pending": "{count, plural, one {# nuevo elemento} other {# nuevos elementos}}",
+  "loading_indicator.label": "Cargando…",
+  "media_gallery.toggle_visible": "Cambiar visibilidad",
+  "missing_indicator.label": "No se encontró",
+  "missing_indicator.sublabel": "No se encontró este recurso",
+  "mute_modal.hide_notifications": "¿Querés ocultar las notificaciones de este usuario?",
+  "navigation_bar.apps": "Aplicaciones móviles",
+  "navigation_bar.blocks": "Usuarios bloqueados",
+  "navigation_bar.community_timeline": "Línea temporal local",
+  "navigation_bar.compose": "Redactar un nuevo toot",
+  "navigation_bar.direct": "Mensajes directos",
+  "navigation_bar.discover": "Descubrir",
+  "navigation_bar.domain_blocks": "Dominios ocultos",
+  "navigation_bar.edit_profile": "Editar perfil",
+  "navigation_bar.favourites": "Favoritos",
+  "navigation_bar.filters": "Palabras silenciadas",
+  "navigation_bar.follow_requests": "Solicitudes de seguimiento",
+  "navigation_bar.follows_and_followers": "Personas seguidas y seguidores",
+  "navigation_bar.info": "Acerca de este servidor",
+  "navigation_bar.keyboard_shortcuts": "Atajos",
+  "navigation_bar.lists": "Listas",
+  "navigation_bar.logout": "Cerrar sesión",
+  "navigation_bar.mutes": "Usuarios silenciados",
+  "navigation_bar.personal": "Personal",
+  "navigation_bar.pins": "Toots fijados",
+  "navigation_bar.preferences": "Configuración",
+  "navigation_bar.public_timeline": "Línea temporal federada",
+  "navigation_bar.security": "Seguridad",
+  "notification.and_n_others": "y {count, plural, one {# otro} other {# otros}}",
+  "notification.favourite": "{name} marcó tu estado como favorito",
+  "notification.follow": "{name} te empezó a seguir",
+  "notification.mention": "{name} te mencionó",
+  "notification.poll": "Finalizó una encuesta en la que votaste",
+  "notification.reblog": "{name} retooteó tu estado",
+  "notifications.clear": "Limpiar notificaciones",
+  "notifications.clear_confirmation": "¿Estás seguro que querés limpiar todas tus notificaciones permanentemente?",
+  "notifications.column_settings.alert": "Notificaciones de escritorio",
+  "notifications.column_settings.favourite": "Favoritos:",
+  "notifications.column_settings.filter_bar.advanced": "Mostrar todas las categorías",
+  "notifications.column_settings.filter_bar.category": "Barra de filtrado rápido",
+  "notifications.column_settings.filter_bar.show": "Mostrar",
+  "notifications.column_settings.follow": "Nuevos seguidores:",
+  "notifications.column_settings.mention": "Menciones:",
+  "notifications.column_settings.poll": "Resultados de la encuesta:",
+  "notifications.column_settings.push": "Notificaciones push",
+  "notifications.column_settings.reblog": "Retoots:",
+  "notifications.column_settings.show": "Mostrar en columna",
+  "notifications.column_settings.sound": "Reproducir sonido",
+  "notifications.filter.all": "Todas",
+  "notifications.filter.boosts": "Retoots",
+  "notifications.filter.favourites": "Favoritos",
+  "notifications.filter.follows": "Seguidores",
+  "notifications.filter.mentions": "Menciones",
+  "notifications.filter.polls": "Resultados de la encuesta",
+  "notifications.group": "{count} notificaciones",
+  "poll.closed": "Cerrada",
+  "poll.refresh": "Refrescar",
+  "poll.total_votes": "{count, plural, one {# voto} other {# votos}}",
+  "poll.vote": "Votar",
+  "poll.voted": "You voted for this answer",
+  "poll_button.add_poll": "Add a poll",
+  "poll_button.remove_poll": "Remove poll",
+  "privacy.change": "Adjust status privacy",
+  "privacy.direct.long": "Post to mentioned users only",
+  "privacy.direct.short": "Direct",
+  "privacy.private.long": "Post to followers only",
+  "privacy.private.short": "Followers-only",
+  "privacy.public.long": "Post to public timelines",
+  "privacy.public.short": "Public",
+  "privacy.unlisted.long": "Do not show in public timelines",
+  "privacy.unlisted.short": "Unlisted",
+  "regeneration_indicator.label": "Loading…",
+  "regeneration_indicator.sublabel": "Your home feed is being prepared!",
+  "relative_time.days": "{number}d",
+  "relative_time.hours": "{number}h",
+  "relative_time.just_now": "now",
+  "relative_time.minutes": "{number}m",
+  "relative_time.seconds": "{number}s",
+  "reply_indicator.cancel": "Cancel",
+  "report.forward": "Forward to {target}",
+  "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
+  "report.hint": "The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:",
+  "report.placeholder": "Additional comments",
+  "report.submit": "Submit",
+  "report.target": "Report {target}",
+  "search.placeholder": "Search",
+  "search_popout.search_format": "Advanced search format",
+  "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
+  "search_popout.tips.hashtag": "hashtag",
+  "search_popout.tips.status": "status",
+  "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
+  "search_popout.tips.user": "user",
+  "search_results.accounts": "People",
+  "search_results.hashtags": "Hashtags",
+  "search_results.statuses": "Toots",
+  "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
+  "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
+  "status.admin_account": "Open moderation interface for @{name}",
+  "status.admin_status": "Open this status in the moderation interface",
+  "status.block": "Block @{name}",
+  "status.cancel_reblog_private": "Unboost",
+  "status.cannot_reblog": "This post cannot be boosted",
+  "status.copy": "Copy link to status",
+  "status.delete": "Delete",
+  "status.detailed_status": "Detailed conversation view",
+  "status.direct": "Direct message @{name}",
+  "status.embed": "Embed",
+  "status.favourite": "Favourite",
+  "status.filtered": "Filtered",
+  "status.load_more": "Load more",
+  "status.media_hidden": "Media hidden",
+  "status.mention": "Mention @{name}",
+  "status.more": "More",
+  "status.mute": "Mute @{name}",
+  "status.mute_conversation": "Mute conversation",
+  "status.open": "Expand this status",
+  "status.pin": "Pin on profile",
+  "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
+  "status.reblog": "Boost",
+  "status.reblog_private": "Boost to original audience",
+  "status.reblogged_by": "{name} boosted",
+  "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.",
+  "status.redraft": "Delete & re-draft",
+  "status.reply": "Reply",
+  "status.replyAll": "Reply to thread",
+  "status.report": "Report @{name}",
+  "status.sensitive_warning": "Sensitive content",
+  "status.share": "Share",
+  "status.show_less": "Show less",
+  "status.show_less_all": "Show less for all",
+  "status.show_more": "Show more",
+  "status.show_more_all": "Show more for all",
+  "status.show_thread": "Show thread",
+  "status.uncached_media_warning": "Not available",
+  "status.unmute_conversation": "Unmute conversation",
+  "status.unpin": "Unpin from profile",
+  "suggestions.dismiss": "Dismiss suggestion",
+  "suggestions.header": "You might be interested in…",
+  "tabs_bar.federated_timeline": "Federated",
+  "tabs_bar.home": "Home",
+  "tabs_bar.local_timeline": "Local",
+  "tabs_bar.notifications": "Notifications",
+  "tabs_bar.search": "Search",
+  "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
+  "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
+  "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
+  "time_remaining.moments": "Moments remaining",
+  "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
+  "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
+  "trends.trending_now": "Trending now",
+  "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
+  "upload_area.title": "Drag & drop to upload",
+  "upload_button.label": "Add media ({formats})",
+  "upload_error.limit": "File upload limit exceeded.",
+  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_form.description": "Describe for the visually impaired",
+  "upload_form.edit": "Edit",
+  "upload_form.undo": "Delete",
+  "upload_modal.analyzing_picture": "Analyzing picture…",
+  "upload_modal.apply": "Apply",
+  "upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
+  "upload_modal.detect_text": "Detect text from picture",
+  "upload_modal.edit_media": "Edit media",
+  "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
+  "upload_modal.preview_label": "Preview ({ratio})",
+  "upload_progress.label": "Uploading...",
+  "video.close": "Close video",
+  "video.exit_fullscreen": "Exit full screen",
+  "video.expand": "Expand video",
+  "video.fullscreen": "Full screen",
+  "video.hide": "Hide video",
+  "video.mute": "Mute sound",
+  "video.pause": "Pause",
+  "video.play": "Play",
+  "video.unmute": "Unmute sound"
+}
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index a033f6e1f..63be0e4c3 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -38,11 +38,11 @@
   "account.unfollow": "Dejar de seguir",
   "account.unmute": "Dejar de silenciar a @{name}",
   "account.unmute_notifications": "Dejar de silenciar las notificaciones de @{name}",
-  "alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
+  "alert.rate_limited.message": "Por favor reintente después de {retry_time, time, medium}.",
   "alert.rate_limited.title": "Tarifa limitada",
   "alert.unexpected.message": "Hubo un error inesperado.",
   "alert.unexpected.title": "¡Ups!",
-  "autosuggest_hashtag.per_week": "{count} per week",
+  "autosuggest_hashtag.per_week": "{count} por semana",
   "boost_modal.combo": "Puedes hacer clic en {combo} para saltar este aviso la próxima vez",
   "bundle_column_error.body": "Algo salió mal al cargar este componente.",
   "bundle_column_error.retry": "Inténtalo de nuevo",
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Responder sobrescribirá el mensaje que estás escribiendo. ¿Estás seguro de que deseas continuar?",
   "confirmations.unfollow.confirm": "Dejar de seguir",
   "confirmations.unfollow.message": "¿Estás seguro de que quieres dejar de seguir a {name}?",
+  "conversation.delete": "Borrar conversación",
+  "conversation.mark_as_read": "Marcar como leído",
+  "conversation.open": "Ver conversación",
+  "conversation.with": "Con {names}",
   "directory.federated": "Desde el fediverso conocido",
   "directory.local": "Sólo de {domain}",
   "directory.new_arrivals": "Recién llegados",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Básico",
   "home.column_settings.show_reblogs": "Mostrar retoots",
   "home.column_settings.show_replies": "Mostrar respuestas",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Actualizar en tiempo real",
   "intervals.full.days": "{number, plural, one {# día} other {# días}}",
   "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
   "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Preferencias",
   "navigation_bar.public_timeline": "Historia federada",
   "navigation_bar.security": "Seguridad",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "y {count, plural, one {# otro} other {# otros}}",
   "notification.favourite": "{name} marcó tu estado como favorito",
   "notification.follow": "{name} te empezó a seguir",
   "notification.mention": "{name} te ha mencionado",
@@ -295,6 +299,7 @@
   "poll.refresh": "Actualizar",
   "poll.total_votes": "{count, plural, one {# voto} other {# votos}}",
   "poll.vote": "Votar",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Añadir una encuesta",
   "poll_button.remove_poll": "Eliminar encuesta",
   "privacy.change": "Ajustar privacidad",
@@ -400,7 +405,7 @@
   "upload_modal.detect_text": "Detectar texto de la imagen",
   "upload_modal.edit_media": "Editar multimedia",
   "upload_modal.hint": "Haga clic o arrastre el círculo en la vista previa para elegir el punto focal que siempre estará a la vista en todas las miniaturas.",
-  "upload_modal.preview_label": "Preview ({ratio})",
+  "upload_modal.preview_label": "Vista previa ({ratio})",
   "upload_progress.label": "Subiendo…",
   "video.close": "Cerrar video",
   "video.exit_fullscreen": "Salir de pantalla completa",
diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json
index 1d1dfd35a..5d3b080de 100644
--- a/app/javascript/mastodon/locales/et.json
+++ b/app/javascript/mastodon/locales/et.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Kohene vastamine kirjutab üle sõnumi, mida hetkel koostad. Oled kindel, et soovid jätkata?",
   "confirmations.unfollow.confirm": "Ära jälgi",
   "confirmations.unfollow.message": "Oled kindel, et ei soovi jälgida {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Värskenda",
   "poll.total_votes": "{count, plural, one {# hääl} other {# hääli}}",
   "poll.vote": "Hääleta",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Lisa küsitlus",
   "poll_button.remove_poll": "Eemalda küsitlus",
   "privacy.change": "Muuda staatuse privaatsust",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index f1fc17fdd..0d272c223 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Orain erantzuteak idazten ari zaren mezua gainidatziko du. Ziur jarraitu nahi duzula?",
   "confirmations.unfollow.confirm": "Utzi jarraitzeari",
   "confirmations.unfollow.message": "Ziur {name} jarraitzeari utzi nahi diozula?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "Fedibertso ezagunekoak",
   "directory.local": "{domain} domeinukoak soilik",
   "directory.new_arrivals": "Iritsi berriak",
@@ -295,6 +299,7 @@
   "poll.refresh": "Berritu",
   "poll.total_votes": "{count, plural, one {boto #} other {# boto}}",
   "poll.vote": "Bozkatu",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Gehitu inkesta bat",
   "poll_button.remove_poll": "Kendu inkesta",
   "privacy.change": "Doitu mezuaren pribatutasuna",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index 9382ec5ee..70c1734cb 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -3,7 +3,7 @@
   "account.badges.bot": "ربات",
   "account.block": "مسدودسازی @{name}",
   "account.block_domain": "پنهان‌سازی همه چیز از سرور {domain}",
-  "account.blocked": "مسدودشده",
+  "account.blocked": "مسدود شده",
   "account.cancel_follow_request": "لغو درخواست پیگیری",
   "account.direct": "پیغام خصوصی به @{name}",
   "account.domain_blocked": "دامین پنهان‌شده",
@@ -16,7 +16,7 @@
   "account.follows.empty": "این کاربر هنوز هیچ کسی را پی نمی‌گیرد.",
   "account.follows_you": "پیگیر شماست",
   "account.hide_reblogs": "پنهان کردن بازبوق‌های @{name}",
-  "account.last_status": "Last active",
+  "account.last_status": "آخرین فعالیت",
   "account.link_verified_on": "مالکیت این نشانی در تاریخ {date} بررسی شد",
   "account.locked_info": "این حساب خصوصی است. صاحب این حساب تصمیم می‌گیرد که چه کسی می‌تواند پیگیرش باشد.",
   "account.media": "عکس و ویدیو",
@@ -25,7 +25,7 @@
   "account.mute": "بی‌صدا کردن @{name}",
   "account.mute_notifications": "بی‌صداکردن اعلان‌ها از طرف @{name}",
   "account.muted": "بی‌صداشده",
-  "account.never_active": "Never",
+  "account.never_active": "هرگز",
   "account.posts": "نوشته‌ها",
   "account.posts_with_replies": "نوشته‌ها و پاسخ‌ها",
   "account.report": "گزارش @{name}",
@@ -38,8 +38,8 @@
   "account.unfollow": "پایان پیگیری",
   "account.unmute": "باصدا کردن @{name}",
   "account.unmute_notifications": "باصداکردن اعلان‌ها از طرف @{name}",
-  "alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
-  "alert.rate_limited.title": "Rate limited",
+  "alert.rate_limited.message": "لطفاً پس از {retry_time, time, medium} دوباره تلاش کنید.",
+  "alert.rate_limited.title": "محدودیت تعداد",
   "alert.unexpected.message": "خطای پیش‌بینی‌نشده‌ای رخ داد.",
   "alert.unexpected.title": "ای وای!",
   "autosuggest_hashtag.per_week": "{count} در هفته",
@@ -53,7 +53,7 @@
   "column.blocks": "کاربران مسدودشده",
   "column.community": "نوشته‌های محلی",
   "column.direct": "پیغام‌های خصوصی",
-  "column.directory": "Browse profiles",
+  "column.directory": "مرور نمایه‌ها",
   "column.domain_blocks": "دامین‌های پنهان‌شده",
   "column.favourites": "پسندیده‌ها",
   "column.follow_requests": "درخواست‌های پیگیری",
@@ -63,7 +63,7 @@
   "column.notifications": "اعلان‌ها",
   "column.pins": "نوشته‌های ثابت",
   "column.public": "نوشته‌های همه‌جا",
-  "column.status": "Toot",
+  "column.status": "بوق",
   "column_back_button.label": "بازگشت",
   "column_header.hide_settings": "نهفتن تنظیمات",
   "column_header.moveLeft_settings": "انتقال ستون به راست",
@@ -101,8 +101,8 @@
   "confirmations.delete_list.message": "آیا واقعاً می‌خواهید این فهرست را برای همیشه پاک کنید؟",
   "confirmations.domain_block.confirm": "پنهان‌سازی کل دامین",
   "confirmations.domain_block.message": "آیا جدی جدی می‌خواهید کل دامین {domain} را مسدود کنید؟ بیشتر وقت‌ها مسدودکردن یا بی‌صداکردن چند حساب کاربری خاص کافی است و توصیه می‌شود. پس از این کار شما هیچ نوشته‌ای را از این دامین در فهرست نوشته‌های عمومی یا اعلان‌هایتان نخواهید دید. پیگیران شما از این دامین هم حذف خواهد شد.",
-  "confirmations.logout.confirm": "Log out",
-  "confirmations.logout.message": "Are you sure you want to log out?",
+  "confirmations.logout.confirm": "خروج",
+  "confirmations.logout.message": "آیا مطمئنید که می‌خواهید خارج شوید؟",
   "confirmations.mute.confirm": "بی‌صدا کن",
   "confirmations.mute.message": "آیا واقعاً می‌خواهید {name} را بی‌صدا کنید؟",
   "confirmations.redraft.confirm": "پاک‌کردن و بازنویسی",
@@ -111,10 +111,14 @@
   "confirmations.reply.message": "اگر الان پاسخ دهید، چیزی که در حال نوشتنش بودید پاک خواهد شد. آیا همین را می‌خواهید؟",
   "confirmations.unfollow.confirm": "لغو پیگیری",
   "confirmations.unfollow.message": "آیا واقعاً می‌خواهید به پیگیری از {name} پایان دهید؟",
-  "directory.federated": "From known fediverse",
-  "directory.local": "From {domain} only",
-  "directory.new_arrivals": "New arrivals",
-  "directory.recently_active": "Recently active",
+  "conversation.delete": "حذف گفتگو",
+  "conversation.mark_as_read": "علامت‌گذاری به عنوان خوانده شده",
+  "conversation.open": "دیدن گفتگو",
+  "conversation.with": "با {names}",
+  "directory.federated": "از سرورهای همسایه",
+  "directory.local": "تنها از {domain}",
+  "directory.new_arrivals": "تازه‌واردان",
+  "directory.recently_active": "کاربران فعال اخیر",
   "embed.instructions": "برای جاگذاری این نوشته در سایت خودتان، کد زیر را کپی کنید.",
   "embed.preview": "نوشتهٔ جاگذاری‌شده این گونه به نظر خواهد رسید:",
   "emoji_button.activity": "فعالیت",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "اصلی",
   "home.column_settings.show_reblogs": "نمایش بازبوق‌ها",
   "home.column_settings.show_replies": "نمایش پاسخ‌ها",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "به‌روزرسانی لحظه‌ای",
   "intervals.full.days": "{number, plural, one {# روز} other {# روز}}",
   "intervals.full.hours": "{number, plural, one {# ساعت} other {# ساعت}}",
   "intervals.full.minutes": "{number, plural, one {# دقیقه} other {# دقیقه}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "ترجیحات",
   "navigation_bar.public_timeline": "نوشته‌های همه‌جا",
   "navigation_bar.security": "امنیت",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "و {count, plural, one {# اعلان دیگر} other {# اعلان دیگر}}",
   "notification.favourite": "‫{name}‬ نوشتهٔ شما را پسندید",
   "notification.follow": "‫{name}‬ پیگیر شما شد",
   "notification.mention": "‫{name}‬ از شما نام برد",
@@ -295,6 +299,7 @@
   "poll.refresh": "به‌روزرسانی",
   "poll.total_votes": "{count, plural, one {# رأی} other {# رأی}}",
   "poll.vote": "رأی",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "افزودن نظرسنجی",
   "poll_button.remove_poll": "حذف نظرسنجی",
   "privacy.change": "تنظیم حریم خصوصی نوشته‌ها",
@@ -369,7 +374,7 @@
   "status.show_more": "نمایش",
   "status.show_more_all": "نمایش بیشتر همه",
   "status.show_thread": "نمایش گفتگو",
-  "status.uncached_media_warning": "Not available",
+  "status.uncached_media_warning": "ناموجود",
   "status.unmute_conversation": "باصداکردن گفتگو",
   "status.unpin": "برداشتن نوشتهٔ ثابت نمایه",
   "suggestions.dismiss": "پیشنهاد را نادیده بگیر",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 01b5edad1..93b770fca 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Jos vastaat nyt, vastaus korvaa tällä hetkellä työstämäsi viestin. Oletko varma, että haluat jatkaa?",
   "confirmations.unfollow.confirm": "Lakkaa seuraamasta",
   "confirmations.unfollow.message": "Haluatko varmasti lakata seuraamasta käyttäjää {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Säädä tuuttauksen näkyvyyttä",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index 7cfe9829a..5120d6bcc 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -39,7 +39,7 @@
   "account.unmute": "Ne plus masquer @{name}",
   "account.unmute_notifications": "Réactiver les notifications de @{name}",
   "alert.rate_limited.message": "Veuillez réessayer après {retry_time, time, medium}.",
-  "alert.rate_limited.title": "Taux limité",
+  "alert.rate_limited.title": "Débit limité",
   "alert.unexpected.message": "Une erreur inattendue s’est produite.",
   "alert.unexpected.title": "Oups !",
   "autosuggest_hashtag.per_week": "{count} par semaine",
@@ -63,19 +63,19 @@
   "column.notifications": "Notifications",
   "column.pins": "Pouets épinglés",
   "column.public": "Fil public global",
-  "column.status": "Toot",
+  "column.status": "Pouet",
   "column_back_button.label": "Retour",
   "column_header.hide_settings": "Masquer les paramètres",
   "column_header.moveLeft_settings": "Déplacer la colonne vers la gauche",
   "column_header.moveRight_settings": "Déplacer la colonne vers la droite",
   "column_header.pin": "Épingler",
   "column_header.show_settings": "Afficher les paramètres",
-  "column_header.unpin": "Retirer",
+  "column_header.unpin": "Désépingler",
   "column_subheading.settings": "Paramètres",
   "community.column_settings.media_only": "Média uniquement",
   "compose_form.direct_message_warning": "Ce pouet sera uniquement envoyé aux personnes mentionnées. Cependant, l’administration de votre instance et des instances réceptrices pourront inspecter ce message.",
-  "compose_form.direct_message_warning_learn_more": "En savoir plus",
-  "compose_form.hashtag_warning": "Ce pouet ne sera pas listé dans les recherches par hashtag car sa visibilité est réglée sur \"non listé\". Seuls les pouets avec une visibilité \"publique\" peuvent être recherchés par hashtag.",
+  "compose_form.direct_message_warning_learn_more": "Plus d'informations",
+  "compose_form.hashtag_warning": "Ce pouet ne sera pas listé dans les recherches par mot-clé car sa visibilité est réglée sur \"non listé\". Seuls les pouets avec une visibilité \"publique\" peuvent être recherchés par mot-clé.",
   "compose_form.lock_disclaimer": "Votre compte n’est pas {locked}. Tout le monde peut vous suivre et voir vos pouets privés.",
   "compose_form.lock_disclaimer.lock": "verrouillé",
   "compose_form.placeholder": "Qu’avez-vous en tête ?",
@@ -87,7 +87,7 @@
   "compose_form.publish_loud": "{publish} !",
   "compose_form.sensitive.hide": "Marquer le média comme sensible",
   "compose_form.sensitive.marked": "Média marqué comme sensible",
-  "compose_form.sensitive.unmarked": "Média non marqué comme sensible",
+  "compose_form.sensitive.unmarked": "Le média n'est pas marqué comme sensible",
   "compose_form.spoiler.marked": "Le texte est caché derrière un avertissement",
   "compose_form.spoiler.unmarked": "Le texte n’est pas caché",
   "compose_form.spoiler_placeholder": "Écrivez ici votre avertissement",
@@ -104,13 +104,17 @@
   "confirmations.logout.confirm": "Déconnexion",
   "confirmations.logout.message": "Êtes-vous sûr de vouloir vous déconnecter ?",
   "confirmations.mute.confirm": "Masquer",
-  "confirmations.mute.message": "Confirmez-vous le masquage de {name} ?",
+  "confirmations.mute.message": "Êtes-vous sûr·e de vouloir masquer {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": "Répondre",
   "confirmations.reply.message": "Répondre maintenant écrasera le message que vous êtes en train de composer. Voulez-vous vraiment continuer ?",
   "confirmations.unfollow.confirm": "Ne plus suivre",
   "confirmations.unfollow.message": "Voulez-vous arrêter de suivre {name} ?",
+  "conversation.delete": "Supprimer la conversation",
+  "conversation.mark_as_read": "Marquer comme lu",
+  "conversation.open": "Afficher la conversation",
+  "conversation.with": "Avec {names}",
   "directory.federated": "De la fédiverse connue",
   "directory.local": "De {domain} seulement",
   "directory.new_arrivals": "Nouveaux arrivants",
@@ -147,7 +151,7 @@
   "empty_column.lists": "Vous n’avez pas encore de liste. Lorsque vous en créerez une, elle apparaîtra ici.",
   "empty_column.mutes": "Vous n’avez pas encore mis d'utilisateur·rice·s en silence.",
   "empty_column.notifications": "Vous n’avez pas encore de notification. Interagissez avec d’autres personnes pour débuter la conversation.",
-  "empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des personnes d’autres instances pour remplir le fil public",
+  "empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des personnes d’autres instances pour le remplir",
   "follow_request.authorize": "Accepter",
   "follow_request.reject": "Rejeter",
   "getting_started.developers": "Développeur·euse·s",
@@ -162,15 +166,15 @@
   "hashtag.column_header.tag_mode.any": "ou {additional}",
   "hashtag.column_header.tag_mode.none": "sans {additional}",
   "hashtag.column_settings.select.no_options_message": "Aucune suggestion trouvée",
-  "hashtag.column_settings.select.placeholder": "Ajouter des hashtags…",
+  "hashtag.column_settings.select.placeholder": "Ajouter des mots-clés…",
   "hashtag.column_settings.tag_mode.all": "Tous ces éléments",
   "hashtag.column_settings.tag_mode.any": "Au moins un de ces éléments",
   "hashtag.column_settings.tag_mode.none": "Aucun de ces éléments",
-  "hashtag.column_settings.tag_toggle": "Inclure des tags additionnels dans cette colonne",
-  "home.column_settings.basic": "Basique",
+  "hashtag.column_settings.tag_toggle": "Inclure des mots-clés additionnels dans cette colonne",
+  "home.column_settings.basic": "Base",
   "home.column_settings.show_reblogs": "Afficher les partages",
   "home.column_settings.show_replies": "Afficher les réponses",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Mettre à jour en temps réel",
   "intervals.full.days": "{number, plural, one {# jour} other {# jours}}",
   "intervals.full.hours": "{number, plural, one {# heure} other {# heures}}",
   "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
@@ -195,7 +199,7 @@
   "keyboard_shortcuts.blocked": "pour ouvrir une liste d’utilisateur·rice·s bloqué·e·s",
   "keyboard_shortcuts.boost": "pour partager",
   "keyboard_shortcuts.column": "pour focaliser un statut dans l’une des colonnes",
-  "keyboard_shortcuts.compose": "pour centrer la zone de rédaction",
+  "keyboard_shortcuts.compose": "pour focaliser la zone de rédaction",
   "keyboard_shortcuts.description": "Description",
   "keyboard_shortcuts.direct": "pour ouvrir une colonne des messages directs",
   "keyboard_shortcuts.down": "pour descendre dans la liste",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Préférences",
   "navigation_bar.public_timeline": "Fil public global",
   "navigation_bar.security": "Sécurité",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "et {count, plural, one {# autre} other {# autres}}",
   "notification.favourite": "{name} a ajouté à ses favoris :",
   "notification.follow": "{name} vous suit",
   "notification.mention": "{name} vous a mentionné :",
@@ -295,6 +299,7 @@
   "poll.refresh": "Actualiser",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Voter",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Ajouter un sondage",
   "poll_button.remove_poll": "Supprimer le sondage",
   "privacy.change": "Ajuster la confidentialité du message",
diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json
index 0967ef424..35639893e 100644
--- a/app/javascript/mastodon/locales/ga.json
+++ b/app/javascript/mastodon/locales/ga.json
@@ -1 +1,419 @@
-{}
+{
+  "account.add_or_remove_from_list": "Add or Remove from lists",
+  "account.badges.bot": "Bot",
+  "account.block": "Block @{name}",
+  "account.block_domain": "Hide everything from {domain}",
+  "account.blocked": "Blocked",
+  "account.cancel_follow_request": "Cancel follow request",
+  "account.direct": "Direct message @{name}",
+  "account.domain_blocked": "Domain hidden",
+  "account.edit_profile": "Edit profile",
+  "account.endorse": "Feature on profile",
+  "account.follow": "Follow",
+  "account.followers": "Followers",
+  "account.followers.empty": "No one follows this user yet.",
+  "account.follows": "Follows",
+  "account.follows.empty": "This user doesn't follow anyone yet.",
+  "account.follows_you": "Follows you",
+  "account.hide_reblogs": "Hide boosts from @{name}",
+  "account.last_status": "Last active",
+  "account.link_verified_on": "Ownership of this link was checked on {date}",
+  "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.",
+  "account.media": "Media",
+  "account.mention": "Mention @{name}",
+  "account.moved_to": "{name} has moved to:",
+  "account.mute": "Mute @{name}",
+  "account.mute_notifications": "Mute notifications from @{name}",
+  "account.muted": "Muted",
+  "account.never_active": "Never",
+  "account.posts": "Toots",
+  "account.posts_with_replies": "Toots and replies",
+  "account.report": "Report @{name}",
+  "account.requested": "Awaiting approval",
+  "account.share": "Share @{name}'s profile",
+  "account.show_reblogs": "Show boosts from @{name}",
+  "account.unblock": "Unblock @{name}",
+  "account.unblock_domain": "Unhide {domain}",
+  "account.unendorse": "Don't feature on profile",
+  "account.unfollow": "Unfollow",
+  "account.unmute": "Unmute @{name}",
+  "account.unmute_notifications": "Unmute notifications from @{name}",
+  "alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
+  "alert.rate_limited.title": "Rate limited",
+  "alert.unexpected.message": "An unexpected error occurred.",
+  "alert.unexpected.title": "Oops!",
+  "autosuggest_hashtag.per_week": "{count} per week",
+  "boost_modal.combo": "You can press {combo} to skip this next time",
+  "bundle_column_error.body": "Something went wrong while loading this component.",
+  "bundle_column_error.retry": "Try again",
+  "bundle_column_error.title": "Network error",
+  "bundle_modal_error.close": "Close",
+  "bundle_modal_error.message": "Something went wrong while loading this component.",
+  "bundle_modal_error.retry": "Try again",
+  "column.blocks": "Blocked users",
+  "column.community": "Local timeline",
+  "column.direct": "Direct messages",
+  "column.directory": "Browse profiles",
+  "column.domain_blocks": "Hidden domains",
+  "column.favourites": "Favourites",
+  "column.follow_requests": "Follow requests",
+  "column.home": "Home",
+  "column.lists": "Lists",
+  "column.mutes": "Muted users",
+  "column.notifications": "Notifications",
+  "column.pins": "Pinned toot",
+  "column.public": "Federated timeline",
+  "column.status": "Toot",
+  "column_back_button.label": "Back",
+  "column_header.hide_settings": "Hide settings",
+  "column_header.moveLeft_settings": "Move column to the left",
+  "column_header.moveRight_settings": "Move column to the right",
+  "column_header.pin": "Pin",
+  "column_header.show_settings": "Show settings",
+  "column_header.unpin": "Unpin",
+  "column_subheading.settings": "Settings",
+  "community.column_settings.media_only": "Media only",
+  "compose_form.direct_message_warning": "This toot will only be sent to all the mentioned users.",
+  "compose_form.direct_message_warning_learn_more": "Learn more",
+  "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
+  "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
+  "compose_form.lock_disclaimer.lock": "locked",
+  "compose_form.placeholder": "What is on your mind?",
+  "compose_form.poll.add_option": "Add a choice",
+  "compose_form.poll.duration": "Poll duration",
+  "compose_form.poll.option_placeholder": "Choice {number}",
+  "compose_form.poll.remove_option": "Remove this choice",
+  "compose_form.publish": "Toot",
+  "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
+  "compose_form.sensitive.marked": "Media is marked as sensitive",
+  "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
+  "compose_form.spoiler.marked": "Text is hidden behind warning",
+  "compose_form.spoiler.unmarked": "Text is not hidden",
+  "compose_form.spoiler_placeholder": "Write your warning here",
+  "confirmation_modal.cancel": "Cancel",
+  "confirmations.block.block_and_report": "Block & Report",
+  "confirmations.block.confirm": "Block",
+  "confirmations.block.message": "Are you sure you want to block {name}?",
+  "confirmations.delete.confirm": "Delete",
+  "confirmations.delete.message": "Are you sure you want to delete this status?",
+  "confirmations.delete_list.confirm": "Delete",
+  "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
+  "confirmations.domain_block.confirm": "Hide entire domain",
+  "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
+  "confirmations.logout.confirm": "Log out",
+  "confirmations.logout.message": "Are you sure you want to log out?",
+  "confirmations.mute.confirm": "Mute",
+  "confirmations.mute.message": "Are you sure you want to mute {name}?",
+  "confirmations.redraft.confirm": "Delete & redraft",
+  "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
+  "confirmations.unfollow.confirm": "Unfollow",
+  "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
+  "directory.federated": "From known fediverse",
+  "directory.local": "From {domain} only",
+  "directory.new_arrivals": "New arrivals",
+  "directory.recently_active": "Recently active",
+  "embed.instructions": "Embed this status on your website by copying the code below.",
+  "embed.preview": "Here is what it will look like:",
+  "emoji_button.activity": "Activity",
+  "emoji_button.custom": "Custom",
+  "emoji_button.flags": "Flags",
+  "emoji_button.food": "Food & Drink",
+  "emoji_button.label": "Insert emoji",
+  "emoji_button.nature": "Nature",
+  "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
+  "emoji_button.objects": "Objects",
+  "emoji_button.people": "People",
+  "emoji_button.recent": "Frequently used",
+  "emoji_button.search": "Search...",
+  "emoji_button.search_results": "Search results",
+  "emoji_button.symbols": "Symbols",
+  "emoji_button.travel": "Travel & Places",
+  "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
+  "empty_column.blocks": "You haven't blocked any users yet.",
+  "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
+  "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
+  "empty_column.domain_blocks": "There are no hidden domains yet.",
+  "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
+  "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
+  "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
+  "empty_column.hashtag": "There is nothing in this hashtag yet.",
+  "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.",
+  "empty_column.home.public_timeline": "the public timeline",
+  "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
+  "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.",
+  "empty_column.mutes": "You haven't muted any users yet.",
+  "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
+  "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other servers to fill it up",
+  "follow_request.authorize": "Authorize",
+  "follow_request.reject": "Reject",
+  "getting_started.developers": "Developers",
+  "getting_started.directory": "Profile directory",
+  "getting_started.documentation": "Documentation",
+  "getting_started.heading": "Getting started",
+  "getting_started.invite": "Invite people",
+  "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
+  "getting_started.security": "Security",
+  "getting_started.terms": "Terms of service",
+  "hashtag.column_header.tag_mode.all": "and {additional}",
+  "hashtag.column_header.tag_mode.any": "or {additional}",
+  "hashtag.column_header.tag_mode.none": "without {additional}",
+  "hashtag.column_settings.select.no_options_message": "No suggestions found",
+  "hashtag.column_settings.select.placeholder": "Enter hashtags…",
+  "hashtag.column_settings.tag_mode.all": "All of these",
+  "hashtag.column_settings.tag_mode.any": "Any of these",
+  "hashtag.column_settings.tag_mode.none": "None of these",
+  "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
+  "home.column_settings.basic": "Basic",
+  "home.column_settings.show_reblogs": "Show boosts",
+  "home.column_settings.show_replies": "Show replies",
+  "home.column_settings.update_live": "Update in real-time",
+  "intervals.full.days": "{number, plural, one {# day} other {# days}}",
+  "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
+  "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
+  "introduction.federation.action": "Next",
+  "introduction.federation.federated.headline": "Federated",
+  "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.",
+  "introduction.federation.home.headline": "Home",
+  "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
+  "introduction.federation.local.headline": "Local",
+  "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
+  "introduction.interactions.action": "Finish toot-orial!",
+  "introduction.interactions.favourite.headline": "Favourite",
+  "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.",
+  "introduction.interactions.reblog.headline": "Boost",
+  "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.",
+  "introduction.interactions.reply.headline": "Reply",
+  "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
+  "introduction.welcome.action": "Let's go!",
+  "introduction.welcome.headline": "First steps",
+  "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
+  "keyboard_shortcuts.back": "to navigate back",
+  "keyboard_shortcuts.blocked": "to open blocked users list",
+  "keyboard_shortcuts.boost": "to boost",
+  "keyboard_shortcuts.column": "to focus a status in one of the columns",
+  "keyboard_shortcuts.compose": "to focus the compose textarea",
+  "keyboard_shortcuts.description": "Description",
+  "keyboard_shortcuts.direct": "to open direct messages column",
+  "keyboard_shortcuts.down": "to move down in the list",
+  "keyboard_shortcuts.enter": "to open status",
+  "keyboard_shortcuts.favourite": "to favourite",
+  "keyboard_shortcuts.favourites": "to open favourites list",
+  "keyboard_shortcuts.federated": "to open federated timeline",
+  "keyboard_shortcuts.heading": "Keyboard Shortcuts",
+  "keyboard_shortcuts.home": "to open home timeline",
+  "keyboard_shortcuts.hotkey": "Hotkey",
+  "keyboard_shortcuts.legend": "to display this legend",
+  "keyboard_shortcuts.local": "to open local timeline",
+  "keyboard_shortcuts.mention": "to mention author",
+  "keyboard_shortcuts.muted": "to open muted users list",
+  "keyboard_shortcuts.my_profile": "to open your profile",
+  "keyboard_shortcuts.notifications": "to open notifications column",
+  "keyboard_shortcuts.pinned": "to open pinned toots list",
+  "keyboard_shortcuts.profile": "to open author's profile",
+  "keyboard_shortcuts.reply": "to reply",
+  "keyboard_shortcuts.requests": "to open follow requests list",
+  "keyboard_shortcuts.search": "to focus search",
+  "keyboard_shortcuts.start": "to open \"get started\" column",
+  "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
+  "keyboard_shortcuts.toggle_sensitivity": "to show/hide media",
+  "keyboard_shortcuts.toot": "to start a brand new toot",
+  "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
+  "keyboard_shortcuts.up": "to move up in the list",
+  "lightbox.close": "Close",
+  "lightbox.next": "Next",
+  "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
+  "lists.account.add": "Add to list",
+  "lists.account.remove": "Remove from list",
+  "lists.delete": "Delete list",
+  "lists.edit": "Edit list",
+  "lists.edit.submit": "Change title",
+  "lists.new.create": "Add list",
+  "lists.new.title_placeholder": "New list title",
+  "lists.search": "Search among people you follow",
+  "lists.subheading": "Your lists",
+  "load_pending": "{count, plural, one {# new item} other {# new items}}",
+  "loading_indicator.label": "Loading...",
+  "media_gallery.toggle_visible": "Toggle visibility",
+  "missing_indicator.label": "Not found",
+  "missing_indicator.sublabel": "This resource could not be found",
+  "mute_modal.hide_notifications": "Hide notifications from this user?",
+  "navigation_bar.apps": "Mobile apps",
+  "navigation_bar.blocks": "Blocked users",
+  "navigation_bar.community_timeline": "Local timeline",
+  "navigation_bar.compose": "Compose new toot",
+  "navigation_bar.direct": "Direct messages",
+  "navigation_bar.discover": "Discover",
+  "navigation_bar.domain_blocks": "Hidden domains",
+  "navigation_bar.edit_profile": "Edit profile",
+  "navigation_bar.favourites": "Favourites",
+  "navigation_bar.filters": "Muted words",
+  "navigation_bar.follow_requests": "Follow requests",
+  "navigation_bar.follows_and_followers": "Follows and followers",
+  "navigation_bar.info": "About this server",
+  "navigation_bar.keyboard_shortcuts": "Hotkeys",
+  "navigation_bar.lists": "Lists",
+  "navigation_bar.logout": "Logout",
+  "navigation_bar.mutes": "Muted users",
+  "navigation_bar.personal": "Personal",
+  "navigation_bar.pins": "Pinned toots",
+  "navigation_bar.preferences": "Preferences",
+  "navigation_bar.public_timeline": "Federated timeline",
+  "navigation_bar.security": "Security",
+  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.favourite": "{name} favourited your status",
+  "notification.follow": "{name} followed you",
+  "notification.mention": "{name} mentioned you",
+  "notification.poll": "A poll you have voted in has ended",
+  "notification.reblog": "{name} boosted your status",
+  "notifications.clear": "Clear notifications",
+  "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
+  "notifications.column_settings.alert": "Desktop notifications",
+  "notifications.column_settings.favourite": "Favourites:",
+  "notifications.column_settings.filter_bar.advanced": "Display all categories",
+  "notifications.column_settings.filter_bar.category": "Quick filter bar",
+  "notifications.column_settings.filter_bar.show": "Show",
+  "notifications.column_settings.follow": "New followers:",
+  "notifications.column_settings.mention": "Mentions:",
+  "notifications.column_settings.poll": "Poll results:",
+  "notifications.column_settings.push": "Push notifications",
+  "notifications.column_settings.reblog": "Boosts:",
+  "notifications.column_settings.show": "Show in column",
+  "notifications.column_settings.sound": "Play sound",
+  "notifications.filter.all": "All",
+  "notifications.filter.boosts": "Boosts",
+  "notifications.filter.favourites": "Favourites",
+  "notifications.filter.follows": "Follows",
+  "notifications.filter.mentions": "Mentions",
+  "notifications.filter.polls": "Poll results",
+  "notifications.group": "{count} notifications",
+  "poll.closed": "Closed",
+  "poll.refresh": "Refresh",
+  "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
+  "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
+  "poll_button.add_poll": "Add a poll",
+  "poll_button.remove_poll": "Remove poll",
+  "privacy.change": "Adjust status privacy",
+  "privacy.direct.long": "Post to mentioned users only",
+  "privacy.direct.short": "Direct",
+  "privacy.private.long": "Post to followers only",
+  "privacy.private.short": "Followers-only",
+  "privacy.public.long": "Post to public timelines",
+  "privacy.public.short": "Public",
+  "privacy.unlisted.long": "Do not show in public timelines",
+  "privacy.unlisted.short": "Unlisted",
+  "regeneration_indicator.label": "Loading…",
+  "regeneration_indicator.sublabel": "Your home feed is being prepared!",
+  "relative_time.days": "{number}d",
+  "relative_time.hours": "{number}h",
+  "relative_time.just_now": "now",
+  "relative_time.minutes": "{number}m",
+  "relative_time.seconds": "{number}s",
+  "reply_indicator.cancel": "Cancel",
+  "report.forward": "Forward to {target}",
+  "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
+  "report.hint": "The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:",
+  "report.placeholder": "Additional comments",
+  "report.submit": "Submit",
+  "report.target": "Report {target}",
+  "search.placeholder": "Search",
+  "search_popout.search_format": "Advanced search format",
+  "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
+  "search_popout.tips.hashtag": "hashtag",
+  "search_popout.tips.status": "status",
+  "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
+  "search_popout.tips.user": "user",
+  "search_results.accounts": "People",
+  "search_results.hashtags": "Hashtags",
+  "search_results.statuses": "Toots",
+  "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
+  "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
+  "status.admin_account": "Open moderation interface for @{name}",
+  "status.admin_status": "Open this status in the moderation interface",
+  "status.block": "Block @{name}",
+  "status.cancel_reblog_private": "Unboost",
+  "status.cannot_reblog": "This post cannot be boosted",
+  "status.copy": "Copy link to status",
+  "status.delete": "Delete",
+  "status.detailed_status": "Detailed conversation view",
+  "status.direct": "Direct message @{name}",
+  "status.embed": "Embed",
+  "status.favourite": "Favourite",
+  "status.filtered": "Filtered",
+  "status.load_more": "Load more",
+  "status.media_hidden": "Media hidden",
+  "status.mention": "Mention @{name}",
+  "status.more": "More",
+  "status.mute": "Mute @{name}",
+  "status.mute_conversation": "Mute conversation",
+  "status.open": "Expand this status",
+  "status.pin": "Pin on profile",
+  "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
+  "status.reblog": "Boost",
+  "status.reblog_private": "Boost to original audience",
+  "status.reblogged_by": "{name} boosted",
+  "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.",
+  "status.redraft": "Delete & re-draft",
+  "status.reply": "Reply",
+  "status.replyAll": "Reply to thread",
+  "status.report": "Report @{name}",
+  "status.sensitive_warning": "Sensitive content",
+  "status.share": "Share",
+  "status.show_less": "Show less",
+  "status.show_less_all": "Show less for all",
+  "status.show_more": "Show more",
+  "status.show_more_all": "Show more for all",
+  "status.show_thread": "Show thread",
+  "status.uncached_media_warning": "Not available",
+  "status.unmute_conversation": "Unmute conversation",
+  "status.unpin": "Unpin from profile",
+  "suggestions.dismiss": "Dismiss suggestion",
+  "suggestions.header": "You might be interested in…",
+  "tabs_bar.federated_timeline": "Federated",
+  "tabs_bar.home": "Home",
+  "tabs_bar.local_timeline": "Local",
+  "tabs_bar.notifications": "Notifications",
+  "tabs_bar.search": "Search",
+  "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
+  "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
+  "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
+  "time_remaining.moments": "Moments remaining",
+  "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
+  "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
+  "trends.trending_now": "Trending now",
+  "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
+  "upload_area.title": "Drag & drop to upload",
+  "upload_button.label": "Add media ({formats})",
+  "upload_error.limit": "File upload limit exceeded.",
+  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_form.description": "Describe for the visually impaired",
+  "upload_form.edit": "Edit",
+  "upload_form.undo": "Delete",
+  "upload_modal.analyzing_picture": "Analyzing picture…",
+  "upload_modal.apply": "Apply",
+  "upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
+  "upload_modal.detect_text": "Detect text from picture",
+  "upload_modal.edit_media": "Edit media",
+  "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
+  "upload_modal.preview_label": "Preview ({ratio})",
+  "upload_progress.label": "Uploading...",
+  "video.close": "Close video",
+  "video.exit_fullscreen": "Exit full screen",
+  "video.expand": "Expand video",
+  "video.fullscreen": "Full screen",
+  "video.hide": "Hide video",
+  "video.mute": "Mute sound",
+  "video.pause": "Pause",
+  "video.play": "Play",
+  "video.unmute": "Unmute sound"
+}
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 3cc44f43e..c5f670b91 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Respostando agora sobreescribirá a mensaxe que está a compoñer. Segura de querer proceder?",
   "confirmations.unfollow.confirm": "Deixar de seguir",
   "confirmations.unfollow.message": "Quere deixar de seguir a {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "Desde o fediverso coñecido",
   "directory.local": "Só desde {domain}",
   "directory.new_arrivals": "Novas achegas",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Básico",
   "home.column_settings.show_reblogs": "Mostrar repeticións",
   "home.column_settings.show_replies": "Mostrar respostas",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Actualizar en tempo real",
   "intervals.full.days": "{number, plural,one {# día} other {# días}}",
   "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
   "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Preferencias",
   "navigation_bar.public_timeline": "Liña temporal federada",
   "navigation_bar.security": "Seguridade",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "e {count, plural, one {# outro} other {# outros}}",
   "notification.favourite": "{name} marcou como favorito o seu estado",
   "notification.follow": "{name} está a seguila",
   "notification.mention": "{name} mencionoute",
@@ -295,6 +299,7 @@
   "poll.refresh": "Actualizar",
   "poll.total_votes": "{count, plural, one {# voto} outros {# votos}}",
   "poll.vote": "Votar",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Engadir sondaxe",
   "poll_button.remove_poll": "Eliminar sondaxe",
   "privacy.change": "Axustar a intimidade do estado",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index b6cc3e6ce..80a072dcc 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "שינוי פרטיות ההודעה",
diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json
index e2d1eb49d..18e68ce7c 100644
--- a/app/javascript/mastodon/locales/hi.json
+++ b/app/javascript/mastodon/locales/hi.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json
index 6daabc694..dcfb92df5 100644
--- a/app/javascript/mastodon/locales/hr.json
+++ b/app/javascript/mastodon/locales/hr.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Podesi status privatnosti",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index f5a02065b..3dd88c078 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -4,7 +4,7 @@
   "account.block": "@{name} letiltása",
   "account.block_domain": "Minden elrejtése innen: {domain}",
   "account.blocked": "Letiltva",
-  "account.cancel_follow_request": "Cancel follow request",
+  "account.cancel_follow_request": "Követési kérelem törlése",
   "account.direct": "Közvetlen üzenet @{name} számára",
   "account.domain_blocked": "Rejtett domain",
   "account.edit_profile": "Profil szerkesztése",
@@ -16,7 +16,7 @@
   "account.follows.empty": "Ez a felhasználó még senkit sem követ.",
   "account.follows_you": "Követ téged",
   "account.hide_reblogs": "@{name} megtolásainak némítása",
-  "account.last_status": "Last active",
+  "account.last_status": "Utoljára aktív",
   "account.link_verified_on": "A linket ellenőriztük: {date}",
   "account.locked_info": "Ez a fiók zárt. A tulaj engedélyezi, ki követheti őt.",
   "account.media": "Média",
@@ -25,7 +25,7 @@
   "account.mute": "@{name} némítása",
   "account.mute_notifications": "@{name} értesítéseinek némítása",
   "account.muted": "Némítva",
-  "account.never_active": "Never",
+  "account.never_active": "Soha",
   "account.posts": "Tülkölés",
   "account.posts_with_replies": "Tülkölés válaszokkal",
   "account.report": "@{name} jelentése",
@@ -38,11 +38,11 @@
   "account.unfollow": "Követés vége",
   "account.unmute": "@{name} némítás feloldása",
   "account.unmute_notifications": "@{name} némított értesítéseinek feloldása",
-  "alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
-  "alert.rate_limited.title": "Rate limited",
+  "alert.rate_limited.message": "Kérlek, próbáld újra {retry_time, time, medium}.",
+  "alert.rate_limited.title": "Forgalomkorlátozás",
   "alert.unexpected.message": "Váratlan hiba történt.",
   "alert.unexpected.title": "Hoppá!",
-  "autosuggest_hashtag.per_week": "{count} per week",
+  "autosuggest_hashtag.per_week": "{count}/hét",
   "boost_modal.combo": "Hogy átugord ezt következő alkalommal, használd {combo}",
   "bundle_column_error.body": "Hiba történt a komponens betöltése közben.",
   "bundle_column_error.retry": "Próbáld újra",
@@ -53,7 +53,7 @@
   "column.blocks": "Letiltott felhasználók",
   "column.community": "Helyi idővonal",
   "column.direct": "Közvetlen üzenetek",
-  "column.directory": "Browse profiles",
+  "column.directory": "Profilok böngészése",
   "column.domain_blocks": "Rejtett domainek",
   "column.favourites": "Kedvencek",
   "column.follow_requests": "Követési kérelmek",
@@ -63,7 +63,7 @@
   "column.notifications": "Értesítések",
   "column.pins": "Kitűzött tülkök",
   "column.public": "Nyilvános idővonal",
-  "column.status": "Toot",
+  "column.status": "Tülk",
   "column_back_button.label": "Vissza",
   "column_header.hide_settings": "Beállítások elrejtése",
   "column_header.moveLeft_settings": "Oszlop elmozdítása balra",
@@ -101,8 +101,8 @@
   "confirmations.delete_list.message": "Biztos, hogy véglegesen törölni szeretnéd ezt a listát?",
   "confirmations.domain_block.confirm": "Teljes domain elrejtése",
   "confirmations.domain_block.message": "Egészen biztos, hogy le szeretnéd tiltani a teljes {domain}-t? A legtöbb esetben néhány célzott tiltás vagy némítás elegendő és kívánatosabb megoldás. Semmilyen tartalmat nem fogsz látni ebből a domainből se idővonalakon, se értesítésekben. Az ebben a domainben lévő követőidet is eltávolítjuk.",
-  "confirmations.logout.confirm": "Log out",
-  "confirmations.logout.message": "Are you sure you want to log out?",
+  "confirmations.logout.confirm": "Kijelentkezés",
+  "confirmations.logout.message": "Biztosan ki akar jelentkezni?",
   "confirmations.mute.confirm": "Némítás",
   "confirmations.mute.message": "Biztos, hogy némítani szeretnéd {name}?",
   "confirmations.redraft.confirm": "Törlés és újraírás",
@@ -111,10 +111,14 @@
   "confirmations.reply.message": "Ha most válaszolsz, ez felülírja a most szerkesztés alatt álló üzenetet. Mégis ezt szeretnéd?",
   "confirmations.unfollow.confirm": "Követés visszavonása",
   "confirmations.unfollow.message": "Biztos, hogy vissza szeretnéd vonni {name} követését?",
-  "directory.federated": "From known fediverse",
-  "directory.local": "From {domain} only",
-  "directory.new_arrivals": "New arrivals",
-  "directory.recently_active": "Recently active",
+  "conversation.delete": "Beszélgetés törlése",
+  "conversation.mark_as_read": "Megjelölés olvasottként",
+  "conversation.open": "Beszélgetés megtekintése",
+  "conversation.with": "{names}-el/al",
+  "directory.federated": "Az ismert fediverzumból",
+  "directory.local": "Csak {domain}-ból/ből",
+  "directory.new_arrivals": "Új csatlakozók",
+  "directory.recently_active": "Nemrég aktív",
   "embed.instructions": "Ágyazd be ezt a tülköt a weboldaladba az alábbi kód kimásolásával.",
   "embed.preview": "Így fog kinézni:",
   "emoji_button.activity": "Aktivitás",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Alapértelmezések",
   "home.column_settings.show_reblogs": "Megtolások mutatása",
   "home.column_settings.show_replies": "Válaszok mutatása",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Frissítés valós időben",
   "intervals.full.days": "{number, plural, one {# nap} other {# nap}}",
   "intervals.full.hours": "{number, plural, one {# óra} other {# óra}}",
   "intervals.full.minutes": "{number, plural, one {# perc} other {# perc}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Beállítások",
   "navigation_bar.public_timeline": "Föderációs idővonal",
   "navigation_bar.security": "Biztonság",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "és {count, plural, one {# másik} other {# másik}}",
   "notification.favourite": "{name} kedvencnek jelölte egy tülködet",
   "notification.follow": "{name} követ téged",
   "notification.mention": "{name} megemlített",
@@ -295,6 +299,7 @@
   "poll.refresh": "Frissítés",
   "poll.total_votes": "{count, plural, one {# szavazat} other {# szavazat}}",
   "poll.vote": "Szavazás",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Új szavazás",
   "poll_button.remove_poll": "Szavazás törlése",
   "privacy.change": "Tülk láthatóságának módosítása",
@@ -369,7 +374,7 @@
   "status.show_more": "Többet",
   "status.show_more_all": "Többet mindenhol",
   "status.show_thread": "Szál mutatása",
-  "status.uncached_media_warning": "Not available",
+  "status.uncached_media_warning": "Nem elérhető",
   "status.unmute_conversation": "Beszélgetés némításának kikapcsolása",
   "status.unpin": "Kitűzés eltávolítása a profilodról",
   "suggestions.dismiss": "Javaslat elvetése",
@@ -385,22 +390,22 @@
   "time_remaining.moments": "Pillanatok vannak hátra",
   "time_remaining.seconds": "{number, plural, one {# másodperc} other {# másodperc}} van hátra",
   "trends.count_by_accounts": "{count} {rawCount, plural, one {résztvevő} other {résztvevő}} beszélget",
-  "trends.trending_now": "Trending now",
+  "trends.trending_now": "Most trendi",
   "ui.beforeunload": "A piszkozatod el fog veszni, ha elhagyod a Mastodon-t.",
   "upload_area.title": "Húzd ide a feltöltéshez",
   "upload_button.label": "Média hozzáadása (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "Túllépted a fájl feltöltési limitet.",
   "upload_error.poll": "Szavazásnál nem lehet fájlt feltölteni.",
   "upload_form.description": "Leírás látáskorlátozottak számára",
-  "upload_form.edit": "Edit",
+  "upload_form.edit": "Szerkesztés",
   "upload_form.undo": "Mégsem",
-  "upload_modal.analyzing_picture": "Analyzing picture…",
-  "upload_modal.apply": "Apply",
-  "upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
-  "upload_modal.detect_text": "Detect text from picture",
-  "upload_modal.edit_media": "Edit media",
-  "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
-  "upload_modal.preview_label": "Preview ({ratio})",
+  "upload_modal.analyzing_picture": "Kép elemzése…",
+  "upload_modal.apply": "Alkalmazás",
+  "upload_modal.description_placeholder": "A gyors, barna róka átugrik a lusta kutya fölött",
+  "upload_modal.detect_text": "Szöveg felismerése a képről",
+  "upload_modal.edit_media": "Média szerkesztése",
+  "upload_modal.hint": "Kattints vagy húzd a kört az előnézetben arra a fókuszpontra, mely minden megjelenített bélyegképen látható kell, legyen.",
+  "upload_modal.preview_label": "Előnézet ({ratio})",
   "upload_progress.label": "Feltöltés...",
   "video.close": "Videó bezárása",
   "video.exit_fullscreen": "Kilépés teljes képernyőből",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index 1484c76df..54077dc05 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Կարգավորել թթի գաղտնիությունը",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index c9e48a1a6..21fe401b8 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Membalas sekarang akan menimpa pesan yang sedang Anda buat. Anda yakin ingin melanjutkan?",
   "confirmations.unfollow.confirm": "Berhenti mengikuti",
   "confirmations.unfollow.message": "Apakah anda ingin berhenti mengikuti {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Tentukan privasi status",
diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json
index 6c1b7fa8b..092b163fb 100644
--- a/app/javascript/mastodon/locales/io.json
+++ b/app/javascript/mastodon/locales/io.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Aranjar privateso di mesaji",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index dc43bcb5c..1f2f6e0e6 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -16,7 +16,7 @@
   "account.follows.empty": "Questo utente non segue ancora nessuno.",
   "account.follows_you": "Ti segue",
   "account.hide_reblogs": "Nascondi condivisioni da @{name}",
-  "account.last_status": "Last active",
+  "account.last_status": "Ultima attività",
   "account.link_verified_on": "La proprietà di questo link è stata controllata il {date}",
   "account.locked_info": "Il livello di privacy di questo account è impostato a \"bloccato\". Il proprietario esamina manualmente le richieste di seguirlo.",
   "account.media": "Media",
@@ -25,7 +25,7 @@
   "account.mute": "Silenzia @{name}",
   "account.mute_notifications": "Silenzia notifiche da @{name}",
   "account.muted": "Silenziato",
-  "account.never_active": "Never",
+  "account.never_active": "Mai",
   "account.posts": "Toot",
   "account.posts_with_replies": "Toot e risposte",
   "account.report": "Segnala @{name}",
@@ -53,7 +53,7 @@
   "column.blocks": "Utenti bloccati",
   "column.community": "Timeline locale",
   "column.direct": "Messaggi diretti",
-  "column.directory": "Browse profiles",
+  "column.directory": "Sfoglia profili",
   "column.domain_blocks": "Domini nascosti",
   "column.favourites": "Apprezzati",
   "column.follow_requests": "Richieste di amicizia",
@@ -101,8 +101,8 @@
   "confirmations.delete_list.message": "Sei sicuro di voler cancellare definitivamente questa lista?",
   "confirmations.domain_block.confirm": "Nascondi intero dominio",
   "confirmations.domain_block.message": "Sei davvero sicuro che vuoi bloccare l'intero {domain}? Nella maggior parte dei casi, pochi blocchi o silenziamenti mirati sono sufficienti e preferibili. Non vedrai nessun contenuto di quel dominio né nelle timeline pubbliche né nelle notifiche. I tuoi seguaci di quel dominio saranno eliminati.",
-  "confirmations.logout.confirm": "Log out",
-  "confirmations.logout.message": "Are you sure you want to log out?",
+  "confirmations.logout.confirm": "Esci",
+  "confirmations.logout.message": "Sei sicuro di voler uscire?",
   "confirmations.mute.confirm": "Silenzia",
   "confirmations.mute.message": "Sei sicuro di voler silenziare {name}?",
   "confirmations.redraft.confirm": "Cancella e riscrivi",
@@ -111,10 +111,14 @@
   "confirmations.reply.message": "Se rispondi ora, il messaggio che stai componendo sarà sovrascritto. Sei sicuro di voler continuare?",
   "confirmations.unfollow.confirm": "Smetti di seguire",
   "confirmations.unfollow.message": "Sei sicuro che non vuoi più seguire {name}?",
-  "directory.federated": "From known fediverse",
-  "directory.local": "From {domain} only",
-  "directory.new_arrivals": "New arrivals",
-  "directory.recently_active": "Recently active",
+  "conversation.delete": "Elimina conversazione",
+  "conversation.mark_as_read": "Segna come letto",
+  "conversation.open": "Visualizza conversazione",
+  "conversation.with": "Con {names}",
+  "directory.federated": "Da un fediverso noto",
+  "directory.local": "Solo da {domain}",
+  "directory.new_arrivals": "Nuovi arrivi",
+  "directory.recently_active": "Attivo di recente",
   "embed.instructions": "Inserisci questo status nel tuo sito copiando il codice qui sotto.",
   "embed.preview": "Ecco come apparirà:",
   "emoji_button.activity": "Attività",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Semplice",
   "home.column_settings.show_reblogs": "Mostra post condivisi",
   "home.column_settings.show_replies": "Mostra risposte",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Aggiorna in tempo reale",
   "intervals.full.days": "{number, plural, one {# giorno} other {# giorni}}",
   "intervals.full.hours": "{number, plural, one {# ora} other {# ore}}",
   "intervals.full.minutes": "{number, plural, one {# minuto} other {# minuti}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Impostazioni",
   "navigation_bar.public_timeline": "Timeline federata",
   "navigation_bar.security": "Sicurezza",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "e {count, plural, one {# other} other {# others}}",
   "notification.favourite": "{name} ha apprezzato il tuo post",
   "notification.follow": "{name} ha iniziato a seguirti",
   "notification.mention": "{name} ti ha menzionato",
@@ -295,6 +299,7 @@
   "poll.refresh": "Aggiorna",
   "poll.total_votes": "{count, plural, one {# voto} other {# voti}}",
   "poll.vote": "Vota",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Aggiungi un sondaggio",
   "poll_button.remove_poll": "Rimuovi sondaggio",
   "privacy.change": "Modifica privacy del post",
@@ -369,7 +374,7 @@
   "status.show_more": "Mostra di più",
   "status.show_more_all": "Mostra di più per tutti",
   "status.show_thread": "Mostra thread",
-  "status.uncached_media_warning": "Not available",
+  "status.uncached_media_warning": "Non disponibile",
   "status.unmute_conversation": "Annulla silenzia conversazione",
   "status.unpin": "Non fissare in cima al profilo",
   "suggestions.dismiss": "Elimina suggerimento",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 64baed71d..d59b2c7f2 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -38,7 +38,7 @@
   "account.unfollow": "フォロー解除",
   "account.unmute": "@{name}さんのミュートを解除",
   "account.unmute_notifications": "@{name}さんからの通知を受け取るようにする",
-  "alert.rate_limited.message": "{retry_time, time, medium} 後に再試行してください。",
+  "alert.rate_limited.message": "{retry_time, time, medium} 以降に再試行してください。",
   "alert.rate_limited.title": "制限に達しました",
   "alert.unexpected.message": "不明なエラーが発生しました。",
   "alert.unexpected.title": "エラー!",
@@ -53,7 +53,7 @@
   "column.blocks": "ブロックしたユーザー",
   "column.community": "ローカルタイムライン",
   "column.direct": "ダイレクトメッセージ",
-  "column.directory": "Browse profiles",
+  "column.directory": "ディレクトリ",
   "column.domain_blocks": "非表示にしたドメイン",
   "column.favourites": "お気に入り",
   "column.follow_requests": "フォローリクエスト",
@@ -63,7 +63,7 @@
   "column.notifications": "通知",
   "column.pins": "固定されたトゥート",
   "column.public": "連合タイムライン",
-  "column.status": "Toot",
+  "column.status": "トゥート",
   "column_back_button.label": "戻る",
   "column_header.hide_settings": "設定を隠す",
   "column_header.moveLeft_settings": "カラムを左に移動する",
@@ -115,7 +115,11 @@
   "confirmations.reply.message": "今返信すると現在作成中のメッセージが上書きされます。本当に実行しますか?",
   "confirmations.unfollow.confirm": "フォロー解除",
   "confirmations.unfollow.message": "本当に{name}さんのフォローを解除しますか?",
-  "directory.federated": "既知の連合全体",
+  "conversation.delete": "このやりとりを削除",
+  "conversation.mark_as_read": "既読にする",
+  "conversation.open": "会話を表示",
+  "conversation.with": "{names}",
+  "directory.federated": "既知の連合より",
   "directory.local": "{domain} のみ",
   "directory.new_arrivals": "新着順",
   "directory.recently_active": "最近の活動順",
@@ -174,7 +178,7 @@
   "home.column_settings.basic": "基本設定",
   "home.column_settings.show_reblogs": "ブースト表示",
   "home.column_settings.show_replies": "返信表示",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "リアルタイムで更新",
   "intervals.full.days": "{number}日",
   "intervals.full.hours": "{number}時間",
   "intervals.full.minutes": "{number}分",
@@ -269,7 +273,7 @@
   "navigation_bar.public_timeline": "連合タイムライン",
   "navigation_bar.misc": "その他",
   "navigation_bar.security": "セキュリティ",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "と、他 {count} 件",
   "notification.favourite": "{name}さんがあなたのトゥートをお気に入りに登録しました",
   "notification.follow": "{name}さんにフォローされました",
   "notification.mention": "{name}さんがあなたに返信しました",
@@ -300,6 +304,7 @@
   "poll.refresh": "更新",
   "poll.total_votes": "{count}票",
   "poll.vote": "投票",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "アンケートを追加",
   "poll_button.remove_poll": "アンケートを削除",
   "privacy.change": "公開範囲を変更",
@@ -390,7 +395,7 @@
   "time_remaining.moments": "まもなく終了",
   "time_remaining.seconds": "残り{number}秒",
   "trends.count_by_accounts": "{count}人がトゥート",
-  "trends.trending_now": "トレンドタグ",
+  "trends.trending_now": "トレンド",
   "ui.beforeunload": "Mastodonから離れると送信前の投稿は失われます。",
   "upload_area.title": "ドラッグ&ドロップでアップロード",
   "upload_button.label": "メディアを追加 ({formats})",
@@ -404,7 +409,7 @@
   "upload_modal.description_placeholder": "素早い茶色の狐はのろまな犬を飛び越える",
   "upload_modal.detect_text": "画像からテキストを検出",
   "upload_modal.edit_media": "メディアを編集",
-  "upload_modal.hint": "画像をクリックするか円をドラッグすると全てのサムネイルで注目する場所を選ぶことができます",
+  "upload_modal.hint": "画像をクリックするか円をドラッグすると全てのサムネイルの中心点を決めることができます",
   "upload_modal.preview_label": "プレビュー ({ratio})",
   "upload_progress.label": "アップロード中...",
   "video.close": "動画を閉じる",
diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json
index e2a6ee6c6..51b7deb5e 100644
--- a/app/javascript/mastodon/locales/ka.json
+++ b/app/javascript/mastodon/locales/ka.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "სტატუსის კონფიდენციალურობის მითითება",
diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json
index a07302f0a..13f2d23d2 100644
--- a/app/javascript/mastodon/locales/kk.json
+++ b/app/javascript/mastodon/locales/kk.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Жауабыңыз жазып жатқан жазбаңыздың үстіне кетеді. Жалғастырамыз ба?",
   "confirmations.unfollow.confirm": "Оқымау",
   "confirmations.unfollow.message": "\"{name} атты қолданушыға енді жазылғыңыз келмей ме?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Жаңарту",
   "poll.total_votes": "{count, plural, one {# дауыс} other {# дауыс}}",
   "poll.vote": "Дауыс беру",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Сауалнама қосу",
   "poll_button.remove_poll": "Сауалнаманы өшіру",
   "privacy.change": "Құпиялылықты реттеу",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 3ec9a8a16..60a197126 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -63,7 +63,7 @@
   "column.notifications": "알림",
   "column.pins": "고정된 툿",
   "column.public": "연합 타임라인",
-  "column.status": "Toot",
+  "column.status": "툿",
   "column_back_button.label": "돌아가기",
   "column_header.hide_settings": "설정 숨기기",
   "column_header.moveLeft_settings": "왼쪽으로 이동",
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "답글을 달기 위해 현재 작성 중인 메시지가 덮어 씌워집니다. 진행하시겠습니까?",
   "confirmations.unfollow.confirm": "언팔로우",
   "confirmations.unfollow.message": "정말로 {name}를 언팔로우하시겠습니까?",
+  "conversation.delete": "대화 삭제",
+  "conversation.mark_as_read": "읽은 상태로 표시",
+  "conversation.open": "대화 보기",
+  "conversation.with": "{names} 와 함께",
   "directory.federated": "알려진 연합우주로부터",
   "directory.local": "{domain}에서만",
   "directory.new_arrivals": "새로운 사람들",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "기본 설정",
   "home.column_settings.show_reblogs": "부스트 표시",
   "home.column_settings.show_replies": "답글 표시",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "실시간 갱신",
   "intervals.full.days": "{number} 일",
   "intervals.full.hours": "{number} 시간",
   "intervals.full.minutes": "{number} 분",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "사용자 설정",
   "navigation_bar.public_timeline": "연합 타임라인",
   "navigation_bar.security": "보안",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "그리고 {count}개의 기타 항목",
   "notification.favourite": "{name}님이 즐겨찾기 했습니다",
   "notification.follow": "{name}님이 나를 팔로우 했습니다",
   "notification.mention": "{name}님이 답글을 보냈습니다",
@@ -295,6 +299,7 @@
   "poll.refresh": "새로고침",
   "poll.total_votes": "{count} 표",
   "poll.vote": "투표",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "투표 추가",
   "poll_button.remove_poll": "투표 삭제",
   "privacy.change": "포스트의 프라이버시 설정을 변경",
diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index 2de037f16..35639893e 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json
index 8d281c9d5..b837cc42b 100644
--- a/app/javascript/mastodon/locales/lv.json
+++ b/app/javascript/mastodon/locales/lv.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Atbildot tagad tava ziņa ko šobrīd raksti tiks pārrakstīta. Vai tiešām vēlies turpināt?",
   "confirmations.unfollow.confirm": "Nesekot",
   "confirmations.unfollow.message": "Vai tiešam vairs nevēlies sekot lietotājam {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json
index 9bd5eef72..da7ddfc80 100644
--- a/app/javascript/mastodon/locales/ms.json
+++ b/app/javascript/mastodon/locales/ms.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 73e7b3905..edba37434 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -16,7 +16,7 @@
   "account.follows.empty": "Deze gebruiker volgt nog niemand.",
   "account.follows_you": "Volgt jou",
   "account.hide_reblogs": "Verberg boosts van @{name}",
-  "account.last_status": "Last active",
+  "account.last_status": "Laatst actief",
   "account.link_verified_on": "Eigendom van deze link is gecontroleerd op {date}",
   "account.locked_info": "De privacystatus van dit account is op besloten gezet. De eigenaar bepaalt handmatig wie hen kan volgen.",
   "account.media": "Media",
@@ -25,7 +25,7 @@
   "account.mute": "Negeer @{name}",
   "account.mute_notifications": "Negeer meldingen van @{name}",
   "account.muted": "Genegeerd",
-  "account.never_active": "Never",
+  "account.never_active": "Nooit",
   "account.posts": "Toots",
   "account.posts_with_replies": "Toots en reacties",
   "account.report": "Rapporteer @{name}",
@@ -38,8 +38,8 @@
   "account.unfollow": "Ontvolgen",
   "account.unmute": "@{name} niet langer negeren",
   "account.unmute_notifications": "@{name} meldingen niet langer negeren",
-  "alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
-  "alert.rate_limited.title": "Rate limited",
+  "alert.rate_limited.message": "Probeer het nog een keer na {retry_time, time, medium}.",
+  "alert.rate_limited.title": "Beperkt te gebruiken",
   "alert.unexpected.message": "Er deed zich een onverwachte fout voor",
   "alert.unexpected.title": "Oeps!",
   "autosuggest_hashtag.per_week": "{count} per week",
@@ -53,7 +53,7 @@
   "column.blocks": "Geblokkeerde gebruikers",
   "column.community": "Lokale tijdlijn",
   "column.direct": "Directe berichten",
-  "column.directory": "Browse profiles",
+  "column.directory": "Gebruikersgids",
   "column.domain_blocks": "Genegeerde servers",
   "column.favourites": "Favorieten",
   "column.follow_requests": "Volgverzoeken",
@@ -101,8 +101,8 @@
   "confirmations.delete_list.message": "Weet je zeker dat je deze lijst definitief wilt verwijderen?",
   "confirmations.domain_block.confirm": "Verberg alles van deze server",
   "confirmations.domain_block.message": "Weet je het echt heel erg zeker dat je alles van {domain} wilt negeren? In de meeste gevallen is het blokkeren of negeren van een paar specifieke personen voldoende en beter. Je zult geen toots van deze server op openbare tijdlijnen zien of in jouw meldingen. Jouw volgers van deze server worden verwijderd.",
-  "confirmations.logout.confirm": "Log out",
-  "confirmations.logout.message": "Are you sure you want to log out?",
+  "confirmations.logout.confirm": "Uitloggen",
+  "confirmations.logout.message": "Weet je zeker dat je wilt uitloggen?",
   "confirmations.mute.confirm": "Negeren",
   "confirmations.mute.message": "Weet je het zeker dat je {name} wilt negeren?",
   "confirmations.redraft.confirm": "Verwijderen en herschrijven",
@@ -111,10 +111,14 @@
   "confirmations.reply.message": "Door nu te reageren overschrijf je de toot die je op dit moment aan het schrijven bent. Weet je zeker dat je verder wil gaan?",
   "confirmations.unfollow.confirm": "Ontvolgen",
   "confirmations.unfollow.message": "Weet je het zeker dat je {name} wilt ontvolgen?",
-  "directory.federated": "From known fediverse",
-  "directory.local": "From {domain} only",
-  "directory.new_arrivals": "New arrivals",
-  "directory.recently_active": "Recently active",
+  "conversation.delete": "Gesprek verwijderen",
+  "conversation.mark_as_read": "Als gelezen markeren",
+  "conversation.open": "Gesprek tonen",
+  "conversation.with": "Met {names}",
+  "directory.federated": "Fediverse (wat bekend is)",
+  "directory.local": "Alleen {domain}",
+  "directory.new_arrivals": "Nieuwe accounts",
+  "directory.recently_active": "Onlangs actief",
   "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",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Algemeen",
   "home.column_settings.show_reblogs": "Boosts tonen",
   "home.column_settings.show_replies": "Reacties tonen",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "In realtime bijwerken",
   "intervals.full.days": "{number, plural, one {# dag} other {# dagen}}",
   "intervals.full.hours": "{number, plural, one {# uur} other {# uur}}",
   "intervals.full.minutes": "{number, plural, one {# minuut} other {# minuten}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Instellingen",
   "navigation_bar.public_timeline": "Globale tijdlijn",
   "navigation_bar.security": "Beveiliging",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "en {count, plural, one {# meer} other {# meer}}",
   "notification.favourite": "{name} voegde jouw toot als favoriet toe",
   "notification.follow": "{name} volgt jou nu",
   "notification.mention": "{name} vermeldde jou",
@@ -295,6 +299,7 @@
   "poll.refresh": "Vernieuwen",
   "poll.total_votes": "{count, plural, one {# stem} other {# stemmen}}",
   "poll.vote": "Stemmen",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Poll toevoegen",
   "poll_button.remove_poll": "Poll verwijderen",
   "privacy.change": "Zichtbaarheid toot aanpassen",
@@ -369,7 +374,7 @@
   "status.show_more": "Meer tonen",
   "status.show_more_all": "Alles meer tonen",
   "status.show_thread": "Gesprek tonen",
-  "status.uncached_media_warning": "Not available",
+  "status.uncached_media_warning": "Niet beschikbaar",
   "status.unmute_conversation": "Gesprek niet langer negeren",
   "status.unpin": "Van profielpagina losmaken",
   "suggestions.dismiss": "Voorstel verwerpen",
diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json
index dda402494..c4003193e 100644
--- a/app/javascript/mastodon/locales/nn.json
+++ b/app/javascript/mastodon/locales/nn.json
@@ -77,11 +77,11 @@
   "compose_form.direct_message_warning_learn_more": "Lær meir",
   "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
   "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
-  "compose_form.lock_disclaimer.lock": "locked",
-  "compose_form.placeholder": "What is on your mind?",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
+  "compose_form.lock_disclaimer.lock": "låst",
+  "compose_form.placeholder": "Kva har du på hjartet?",
+  "compose_form.poll.add_option": "Legg til eit punkt",
+  "compose_form.poll.duration": "Varigheit for spørring",
+  "compose_form.poll.option_placeholder": "Val {number}",
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json
index 8fc722037..8fe7c9cfd 100644
--- a/app/javascript/mastodon/locales/no.json
+++ b/app/javascript/mastodon/locales/no.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Justér synlighet",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index d5abe89fb..550057f23 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -4,7 +4,7 @@
   "account.block": "Blocar @{name}",
   "account.block_domain": "Tot amagar del domeni {domain}",
   "account.blocked": "Blocat",
-  "account.cancel_follow_request": "Cancel follow request",
+  "account.cancel_follow_request": "Anullar la demanda de seguiment",
   "account.direct": "Escriure un MP a @{name}",
   "account.domain_blocked": "Domeni amagat",
   "account.edit_profile": "Modificar lo perfil",
@@ -16,7 +16,7 @@
   "account.follows.empty": "Aqueste utilizaire sèc pas degun pel moment.",
   "account.follows_you": "Vos sèc",
   "account.hide_reblogs": "Rescondre los partatges de @{name}",
-  "account.last_status": "Last active",
+  "account.last_status": "Darrièra activitat",
   "account.link_verified_on": "La proprietat d’aqueste ligam foguèt verificada lo {date}",
   "account.locked_info": "L’estatut de privacitat del compte es configurat sus clavat. Lo proprietari causís qual pòt sègre son compte.",
   "account.media": "Mèdias",
@@ -25,7 +25,7 @@
   "account.mute": "Rescondre @{name}",
   "account.mute_notifications": "Rescondre las notificacions de @{name}",
   "account.muted": "Mes en silenci",
-  "account.never_active": "Never",
+  "account.never_active": "Jamai",
   "account.posts": "Tuts",
   "account.posts_with_replies": "Tuts e responsas",
   "account.report": "Senhalar @{name}",
@@ -38,11 +38,11 @@
   "account.unfollow": "Quitar de sègre",
   "account.unmute": "Quitar de rescondre @{name}",
   "account.unmute_notifications": "Mostrar las notificacions de @{name}",
-  "alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
-  "alert.rate_limited.title": "Rate limited",
+  "alert.rate_limited.message": "Mercés de tornar ensajar aprèp {retry_time, time, medium}.",
+  "alert.rate_limited.title": "Taus limitat",
   "alert.unexpected.message": "Una error s’es producha.",
   "alert.unexpected.title": "Ops !",
-  "autosuggest_hashtag.per_week": "{count} per week",
+  "autosuggest_hashtag.per_week": "{count} per setmana",
   "boost_modal.combo": "Podètz botar {combo} per passar aquò lo còp que ven",
   "bundle_column_error.body": "Quicòm a fach mèuca pendent lo cargament d’aqueste compausant.",
   "bundle_column_error.retry": "Tornar ensajar",
@@ -53,7 +53,7 @@
   "column.blocks": "Personas blocadas",
   "column.community": "Flux public local",
   "column.direct": "Messatges dirèctes",
-  "column.directory": "Browse profiles",
+  "column.directory": "Percórrer los perfils",
   "column.domain_blocks": "Domenis resconduts",
   "column.favourites": "Favorits",
   "column.follow_requests": "Demandas d’abonament",
@@ -63,7 +63,7 @@
   "column.notifications": "Notificacions",
   "column.pins": "Tuts penjats",
   "column.public": "Flux public global",
-  "column.status": "Toot",
+  "column.status": "Tut",
   "column_back_button.label": "Tornar",
   "column_header.hide_settings": "Amagar los paramètres",
   "column_header.moveLeft_settings": "Desplaçar la colomna a man drecha",
@@ -101,8 +101,8 @@
   "confirmations.delete_list.message": "Volètz vertadièrament suprimir aquesta lista per totjorn ?",
   "confirmations.domain_block.confirm": "Amagar tot lo domeni",
   "confirmations.domain_block.message": "Volètz vertadièrament blocar complètament {domain} ? De còps cal pas que blocar o rescondre unas personas solament.\nVeiretz pas cap de contengut d’aquel domeni dins cap de flux public o dins vòstras notificacions. Vòstres seguidors d’aquel domeni seràn levats.",
-  "confirmations.logout.confirm": "Log out",
-  "confirmations.logout.message": "Are you sure you want to log out?",
+  "confirmations.logout.confirm": "Desconnexion",
+  "confirmations.logout.message": "Volètz vertadièrament vos desconnectar ?",
   "confirmations.mute.confirm": "Rescondre",
   "confirmations.mute.message": "Volètz vertadièrament rescondre {name} ?",
   "confirmations.redraft.confirm": "Escafar & tornar formular",
@@ -111,10 +111,14 @@
   "confirmations.reply.message": "Respondre remplaçarà lo messatge que sètz a escriure. Volètz vertadièrament contunhar ?",
   "confirmations.unfollow.confirm": "Quitar de sègre",
   "confirmations.unfollow.message": "Volètz vertadièrament quitar de sègre {name} ?",
-  "directory.federated": "From known fediverse",
-  "directory.local": "From {domain} only",
-  "directory.new_arrivals": "New arrivals",
-  "directory.recently_active": "Recently active",
+  "conversation.delete": "Suprimir la conversacion",
+  "conversation.mark_as_read": "Marcar coma legida",
+  "conversation.open": "Veire la conversacion",
+  "conversation.with": "Amb {names}",
+  "directory.federated": "Del fediverse conegut",
+  "directory.local": "Solament de {domain}",
+  "directory.new_arrivals": "Nòus-venguts",
+  "directory.recently_active": "Actius fa res",
   "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",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Basic",
   "home.column_settings.show_reblogs": "Mostrar los partatges",
   "home.column_settings.show_replies": "Mostrar las responsas",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Actualizacion en dirècte",
   "intervals.full.days": "{number, plural, one {# jorn} other {# jorns}}",
   "intervals.full.hours": "{number, plural, one {# ora} other {# oras}}",
   "intervals.full.minutes": "{number, plural, one {# minuta} other {# minutas}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Preferéncias",
   "navigation_bar.public_timeline": "Flux public global",
   "navigation_bar.security": "Seguretat",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "e {count, plural, un {# autre} other {# autres}}",
   "notification.favourite": "{name} a ajustat a sos favorits",
   "notification.follow": "{name} vos sèc",
   "notification.mention": "{name} vos a mencionat",
@@ -295,6 +299,7 @@
   "poll.refresh": "Actualizar",
   "poll.total_votes": "{count, plural, one {# vòte} other {# vòtes}}",
   "poll.vote": "Votar",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Ajustar un sondatge",
   "poll_button.remove_poll": "Levar lo sondatge",
   "privacy.change": "Ajustar la confidencialitat del messatge",
@@ -369,7 +374,7 @@
   "status.show_more": "Desplegar",
   "status.show_more_all": "Los desplegar totes",
   "status.show_thread": "Mostrar lo fil",
-  "status.uncached_media_warning": "Not available",
+  "status.uncached_media_warning": "Pas disponible",
   "status.unmute_conversation": "Tornar mostrar la conversacion",
   "status.unpin": "Tirar del perfil",
   "suggestions.dismiss": "Regetar la suggestion",
@@ -385,22 +390,22 @@
   "time_remaining.moments": "Moments restants",
   "time_remaining.seconds": "demòra{number, plural, one { # segonda} other {n # segondas}}",
   "trends.count_by_accounts": "{count} {rawCount, plural, one {person} ne charra other {people}} ne charran",
-  "trends.trending_now": "Trending now",
+  "trends.trending_now": "Tendéncia del moment",
   "ui.beforeunload": "Vòstre brolhon serà perdut se quitatz Mastodon.",
   "upload_area.title": "Lisatz e depausatz per mandar",
   "upload_button.label": "Ajustar un mèdia (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "Talha maximum pels mandadís subrepassada.",
   "upload_error.poll": "Lo mandadís de fichièr es pas autorizat pels sondatges.",
   "upload_form.description": "Descripcion pels mal vesents",
-  "upload_form.edit": "Edit",
+  "upload_form.edit": "Modificar",
   "upload_form.undo": "Suprimir",
-  "upload_modal.analyzing_picture": "Analyzing picture…",
-  "upload_modal.apply": "Apply",
-  "upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
-  "upload_modal.detect_text": "Detect text from picture",
-  "upload_modal.edit_media": "Edit media",
-  "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
-  "upload_modal.preview_label": "Preview ({ratio})",
+  "upload_modal.analyzing_picture": "Analisi de l’imatge…",
+  "upload_modal.apply": "Aplicar",
+  "upload_modal.description_placeholder": "Lo dròlle bilingüe manja un yaourt de ròcs exagonals e kiwis verds farà un an mai",
+  "upload_modal.detect_text": "Detectar lo tèxt de l’imatge",
+  "upload_modal.edit_media": "Modificar lo mèdia",
+  "upload_modal.hint": "Clicatz o lissatz lo cercle de l’apercebut per causir lo ponch que serà totjorn visible dins las vinhetas.",
+  "upload_modal.preview_label": "Apercebut ({ratio})",
   "upload_progress.label": "Mandadís…",
   "video.close": "Tampar la vidèo",
   "video.exit_fullscreen": "Sortir plen ecran",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index 395f3927a..b5af4a49a 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -105,8 +105,8 @@
   "confirmations.delete_list.message": "Czy na pewno chcesz bezpowrotnie usunąć tą listę?",
   "confirmations.domain_block.confirm": "Ukryj wszysyko z domeny",
   "confirmations.domain_block.message": "Czy na pewno chcesz zablokować całą domenę {domain}? Zwykle lepszym rozwiązaniem jest blokada lub wyciszenie kilku użytkowników.",
-  "confirmations.logout.confirm": "Log out",
-  "confirmations.logout.message": "Are you sure you want to log out?",
+  "confirmations.logout.confirm": "Wyloguj",
+  "confirmations.logout.message": "Czy na pewno chcesz się wylogować?",
   "confirmations.mute.confirm": "Wycisz",
   "confirmations.mute.message": "Czy na pewno chcesz wyciszyć {name}?",
   "confirmations.redraft.confirm": "Usuń i przeredaguj",
@@ -115,6 +115,10 @@
   "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.delete": "Usuń rozmowę",
+  "conversation.mark_as_read": "Oznacz jako przeczytane",
+  "conversation.open": "Zobacz rozmowę",
+  "conversation.with": "Z {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -300,6 +304,7 @@
   "poll.refresh": "Odśwież",
   "poll.total_votes": "{count, plural, one {# głos} few {# głosy} many {# głosów} other {# głosów}}",
   "poll.vote": "Zagłosuj",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Dodaj głosowanie",
   "poll_button.remove_poll": "Usuń głosowanie",
   "privacy.change": "Dostosuj widoczność wpisów",
@@ -397,7 +402,7 @@
   "upload_error.limit": "Przekroczono limit plików do wysłania.",
   "upload_error.poll": "Dołączanie plików nie dozwolone z głosowaniami.",
   "upload_form.description": "Wprowadź opis dla niewidomych i niedowidzących",
-  "upload_form.edit": "Edit",
+  "upload_form.edit": "Edytuj",
   "upload_form.undo": "Usuń",
   "upload_modal.analyzing_picture": "Analyzing picture…",
   "upload_modal.apply": "Zastosuj",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index debf9e6f6..4bc703206 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -4,7 +4,7 @@
   "account.block": "Bloquear @{name}",
   "account.block_domain": "Esconder tudo de {domain}",
   "account.blocked": "Bloqueado",
-  "account.cancel_follow_request": "Cancel follow request",
+  "account.cancel_follow_request": "Cancelar solicitação para seguir",
   "account.direct": "Direct Message @{name}",
   "account.domain_blocked": "Domínio escondido",
   "account.edit_profile": "Editar perfil",
@@ -16,7 +16,7 @@
   "account.follows.empty": "Esse usuário não segue ninguém no momento.",
   "account.follows_you": "Segue você",
   "account.hide_reblogs": "Esconder compartilhamentos de @{name}",
-  "account.last_status": "Last active",
+  "account.last_status": "Última atividade",
   "account.link_verified_on": "A posse desse link foi verificada em {date}",
   "account.locked_info": "Essa conta está trancada. Se você a seguir sua solicitação será revisada manualmente.",
   "account.media": "Mídia",
@@ -25,7 +25,7 @@
   "account.mute": "Silenciar @{name}",
   "account.mute_notifications": "Silenciar notificações de @{name}",
   "account.muted": "Silenciado",
-  "account.never_active": "Never",
+  "account.never_active": "Nunca",
   "account.posts": "Toots",
   "account.posts_with_replies": "Toots e respostas",
   "account.report": "Denunciar @{name}",
@@ -38,11 +38,11 @@
   "account.unfollow": "Deixar de seguir",
   "account.unmute": "Não silenciar @{name}",
   "account.unmute_notifications": "Retirar silêncio das notificações vindas de @{name}",
-  "alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
+  "alert.rate_limited.message": "Por favor tente novamente após {retry_time, time, medium}.",
   "alert.rate_limited.title": "Rate limited",
   "alert.unexpected.message": "Um erro inesperado ocorreu.",
   "alert.unexpected.title": "Eita!",
-  "autosuggest_hashtag.per_week": "{count} per week",
+  "autosuggest_hashtag.per_week": "{count} por semana",
   "boost_modal.combo": "Você pode pressionar {combo} para ignorar este diálogo na próxima vez",
   "bundle_column_error.body": "Algo de errado aconteceu enquanto este componente era carregado.",
   "bundle_column_error.retry": "Tente novamente",
@@ -53,7 +53,7 @@
   "column.blocks": "Usuários bloqueados",
   "column.community": "Local",
   "column.direct": "Mensagens diretas",
-  "column.directory": "Browse profiles",
+  "column.directory": "Explorar perfis",
   "column.domain_blocks": "Domínios escondidos",
   "column.favourites": "Favoritos",
   "column.follow_requests": "Seguidores pendentes",
@@ -63,7 +63,7 @@
   "column.notifications": "Notificações",
   "column.pins": "Postagens fixadas",
   "column.public": "Global",
-  "column.status": "Toot",
+  "column.status": "Publicar",
   "column_back_button.label": "Voltar",
   "column_header.hide_settings": "Esconder configurações",
   "column_header.moveLeft_settings": "Mover coluna para a esquerda",
@@ -101,8 +101,8 @@
   "confirmations.delete_list.message": "Você tem certeza que quer deletar permanentemente a lista?",
   "confirmations.domain_block.confirm": "Esconder o domínio inteiro",
   "confirmations.domain_block.message": "Você quer mesmo bloquear {domain} inteiro? Na maioria dos casos, silenciar ou bloquear alguns usuários é o suficiente e o recomendado. Você não vai ver conteúdo desse domínio em nenhuma das timelines públicas ou nas suas notificações. Seus seguidores desse domínio serão removidos.",
-  "confirmations.logout.confirm": "Log out",
-  "confirmations.logout.message": "Are you sure you want to log out?",
+  "confirmations.logout.confirm": "Sair",
+  "confirmations.logout.message": "Tem certeza que deseja encerrar a sessão?",
   "confirmations.mute.confirm": "Silenciar",
   "confirmations.mute.message": "Você tem certeza de que quer silenciar {name}?",
   "confirmations.redraft.confirm": "Apagar & usar como rascunho",
@@ -111,10 +111,14 @@
   "confirmations.reply.message": "Responder agora vai sobrescrever a mensagem que você está compondo. Você tem certeza que quer continuar?",
   "confirmations.unfollow.confirm": "Deixar de seguir",
   "confirmations.unfollow.message": "Você tem certeza de que quer deixar de seguir {name}?",
-  "directory.federated": "From known fediverse",
+  "conversation.delete": "Excluir conversa",
+  "conversation.mark_as_read": "Marcar como lida",
+  "conversation.open": "Ver conversa",
+  "conversation.with": "Com {names}",
+  "directory.federated": "De fediverso conhecido",
   "directory.local": "From {domain} only",
-  "directory.new_arrivals": "New arrivals",
-  "directory.recently_active": "Recently active",
+  "directory.new_arrivals": "Acabaram de chegar",
+  "directory.recently_active": "Reverta esta propriedade para seu valor padrão",
   "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",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Básico",
   "home.column_settings.show_reblogs": "Mostrar compartilhamentos",
   "home.column_settings.show_replies": "Mostrar as respostas",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Atualizar em tempo real",
   "intervals.full.days": "{number, plural, one {# dia} other {# dias}}",
   "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
   "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
@@ -236,7 +240,7 @@
   "lists.new.title_placeholder": "Novo título da lista",
   "lists.search": "Procurar entre as pessoas que você segue",
   "lists.subheading": "Suas listas",
-  "load_pending": "{count, plural, one {# new item} other {# new items}}",
+  "load_pending": "{count, plural, one {# novo item} other {# novos items}}",
   "loading_indicator.label": "Carregando...",
   "media_gallery.toggle_visible": "Esconder/Mostrar",
   "missing_indicator.label": "Não encontrado",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Preferências",
   "navigation_bar.public_timeline": "Global",
   "navigation_bar.security": "Segurança",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "and {count, plural, one {# outro} other {# outros}}",
   "notification.favourite": "{name} adicionou a sua postagem aos favoritos",
   "notification.follow": "{name} te seguiu",
   "notification.mention": "{name} te mencionou",
@@ -295,6 +299,7 @@
   "poll.refresh": "Atualizar",
   "poll.total_votes": "{count, plural, one {# voto} other {# votos}}",
   "poll.vote": "Votar",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Adicionar uma enquete",
   "poll_button.remove_poll": "Remover enquete",
   "privacy.change": "Ajustar a privacidade da mensagem",
@@ -330,11 +335,11 @@
   "search_results.accounts": "Pessoas",
   "search_results.hashtags": "Hashtags",
   "search_results.statuses": "Toots",
-  "search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
+  "search_results.statuses_fts_disabled": "Pesquisar toots por seu conteúdo não está habilitado neste servidor Mastodon.",
   "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
   "status.admin_account": "Abrir interface de moderação para @{name}",
   "status.admin_status": "Abrir esse status na interface de moderação",
-  "status.block": "Block @{name}",
+  "status.block": "Bloquear @{name}",
   "status.cancel_reblog_private": "Desfazer compartilhamento",
   "status.cannot_reblog": "Esta postagem não pode ser compartilhada",
   "status.copy": "Copiar o link para o status",
@@ -385,19 +390,19 @@
   "time_remaining.moments": "Momentos restantes",
   "time_remaining.seconds": "{number, plural, one {# segundo restante} other {# segundos restantes}}",
   "trends.count_by_accounts": "{count} {rawCount, plural, one {pessoa} other {pessoas}} falando sobre",
-  "trends.trending_now": "Trending now",
+  "trends.trending_now": "Em alta no momento",
   "ui.beforeunload": "Seu rascunho será perdido se você sair do Mastodon.",
   "upload_area.title": "Arraste e solte para enviar",
   "upload_button.label": "Adicionar mídia (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "Limite de envio de arquivos excedido.",
   "upload_error.poll": "Envio de arquivos não é permitido com enquetes.",
   "upload_form.description": "Descreva a imagem para deficientes visuais",
-  "upload_form.edit": "Edit",
+  "upload_form.edit": "Editar",
   "upload_form.undo": "Remover",
-  "upload_modal.analyzing_picture": "Analyzing picture…",
-  "upload_modal.apply": "Apply",
-  "upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
-  "upload_modal.detect_text": "Detect text from picture",
+  "upload_modal.analyzing_picture": "Analisando imagem…",
+  "upload_modal.apply": "Aplicar",
+  "upload_modal.description_placeholder": "Grave e cabisbaixo, o filho justo zelava pela querida mãe doente",
+  "upload_modal.detect_text": "Detectar texto da imagem",
   "upload_modal.edit_media": "Edit media",
   "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
   "upload_modal.preview_label": "Preview ({ratio})",
diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json
index feba8fd9a..b286dd622 100644
--- a/app/javascript/mastodon/locales/pt-PT.json
+++ b/app/javascript/mastodon/locales/pt-PT.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Responder agora irá reescrever a mensagem que estás a compor actualmente. Tens a certeza que queres continuar?",
   "confirmations.unfollow.confirm": "Deixar de seguir",
   "confirmations.unfollow.message": "De certeza que queres deixar de seguir {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Recarregar",
   "poll.total_votes": "{contar, plural, um {# vote} outro {# votes}}",
   "poll.vote": "Votar",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Adicionar votação",
   "poll_button.remove_poll": "Remover votação",
   "privacy.change": "Ajustar a privacidade da mensagem",
diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json
index 038b8ddd4..8bda8c060 100644
--- a/app/javascript/mastodon/locales/ro.json
+++ b/app/javascript/mastodon/locales/ro.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Răspunzând la asta acum, mesajul pe care îl compui în prezent se va șterge. Ești sigur că vrei să continui?",
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Cine vede asta",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 69bd5a422..82194d2c6 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "При ответе текст набираемого сообщения будет перезаписан. Продолжить?",
   "confirmations.unfollow.confirm": "Отписаться",
   "confirmations.unfollow.message": "Вы уверены, что хотите отписаться от {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Обновить",
   "poll.total_votes": "{count, plural, one {# голос} few {# голоса} many {# голосов} other {# голосов}}",
   "poll.vote": "Голосовать",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Добавить опрос",
   "poll_button.remove_poll": "Удалить опрос",
   "privacy.change": "Изменить видимость статуса",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index 89a472d89..07616931f 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -63,7 +63,7 @@
   "column.notifications": "Oboznámenia",
   "column.pins": "Pripnuté príspevky",
   "column.public": "Federovaná časová os",
-  "column.status": "Toot",
+  "column.status": "Príspevok",
   "column_back_button.label": "Späť",
   "column_header.hide_settings": "Skryť nastavenia",
   "column_header.moveLeft_settings": "Presuň stĺpec doľava",
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Odpovedaním akurát teraz prepíšeš správu, ktorú máš práve rozpísanú. Si si istý/á, že chceš pokračovať?",
   "confirmations.unfollow.confirm": "Nesleduj",
   "confirmations.unfollow.message": "Naozaj chceš prestať sledovať {name}?",
+  "conversation.delete": "Vymaž konverzáciu",
+  "conversation.mark_as_read": "Označ za prečítané",
+  "conversation.open": "Ukáž konverzáciu",
+  "conversation.with": "S {names}",
   "directory.federated": "Zo známého fedivesmíru",
   "directory.local": "Iba z {domain}",
   "directory.new_arrivals": "Nové príchody",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "Základné",
   "home.column_settings.show_reblogs": "Zobraziť povýšené",
   "home.column_settings.show_replies": "Ukázať odpovede",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "Aktualizuj v reálnom čase",
   "intervals.full.days": "{number, plural, one {# deň} few {# dní} many {# dní} other {# dní}}",
   "intervals.full.hours": "{number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodín}}",
   "intervals.full.minutes": "{number, plural, one {# minúta} few {# minút} many {# minút} other {# minút}}",
@@ -264,7 +268,7 @@
   "navigation_bar.preferences": "Voľby",
   "navigation_bar.public_timeline": "Federovaná časová os",
   "navigation_bar.security": "Zabezbečenie",
-  "notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
+  "notification.and_n_others": "a {count, plural,one {# ostatné} other {# ostatných}}",
   "notification.favourite": "{name} si obľúbil/a tvoj príspevok",
   "notification.follow": "{name} ťa začal/a následovať",
   "notification.mention": "{name} ťa spomenul/a",
@@ -295,6 +299,7 @@
   "poll.refresh": "Obnov",
   "poll.total_votes": "{count, plural, one {# hlas} few {# hlasov} many {# hlasov} other {# hlasov}}",
   "poll.vote": "Hlasuj",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Pridaj anketu",
   "poll_button.remove_poll": "Odstráň anketu",
   "privacy.change": "Uprav súkromie príspevku",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index d7d78c41c..86091e4a7 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Odgovarjanje bo prepisalo sporočilo, ki ga trenutno sestavljate. Ali ste prepričani, da želite nadaljevati?",
   "confirmations.unfollow.confirm": "Prenehaj slediti",
   "confirmations.unfollow.message": "Ali ste prepričani, da ne želite več slediti {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Osveži",
   "poll.total_votes": "{count, plural,one {# glas} other {# glasov}}",
   "poll.vote": "Glasuj",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Dodaj anketo",
   "poll_button.remove_poll": "Odstrani anketo",
   "privacy.change": "Prilagodi zasebnost statusa",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index 0f851051c..66b939682 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Përgjigja tani do të shkaktojë mbishkrimin e mesazhit që po hartoni. Jeni i sigurt se doni të vazhdohet më tej?",
   "confirmations.unfollow.confirm": "Resht së ndjekuri",
   "confirmations.unfollow.message": "Jeni i sigurt se doni të mos ndiqet më {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Rregulloni privatësi gjendje",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index fb6a365ce..f9144348d 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Podesi status privatnosti",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index 064934f54..c7adda11a 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Подеси статус приватности",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index f666a4b6e..449b226f0 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Om du svarar nu kommer det att ersätta meddelandet du håller på att skriva. Är du säker på att du vill fortsätta?",
   "confirmations.unfollow.confirm": "Sluta följa",
   "confirmations.unfollow.message": "Är du säker på att du vill sluta följa {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Ladda om",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Rösta",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Justera sekretess",
diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json
index 3caf301d0..c020bafb3 100644
--- a/app/javascript/mastodon/locales/ta.json
+++ b/app/javascript/mastodon/locales/ta.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "இப்போது பதில், தற்போது நீங்கள் உருவாக்கும் செய்தி மேலெழுதப்படும். நீங்கள் தொடர விரும்புகிறீர்களா?",
   "confirmations.unfollow.confirm": "பின்தொடராட்",
   "confirmations.unfollow.message": "நிச்சயமாக நீங்கள் பின்தொடர விரும்புகிறீர்களா {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "பத்துயிர்ப்ப?ட்டு",
   "poll.total_votes": "{count, plural, one {# vote} மற்ற {# votes}}",
   "poll.vote": "வாக்களி",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "வாக்கெடுப்பைச் சேர்க்கவும்",
   "poll_button.remove_poll": "வாக்கெடுப்பை அகற்று",
   "privacy.change": "நிலை தனியுரிமை",
diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json
index 5827dbb3a..ad99afcf4 100644
--- a/app/javascript/mastodon/locales/te.json
+++ b/app/javascript/mastodon/locales/te.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "ఇప్పుడే ప్రత్యుత్తరం ఇస్తే మీరు ప్రస్తుతం వ్రాస్తున్న సందేశం తిరగరాయబడుతుంది. మీరు ఖచ్చితంగా కొనసాగించాలనుకుంటున్నారా?",
   "confirmations.unfollow.confirm": "అనుసరించవద్దు",
   "confirmations.unfollow.message": "{name}ను మీరు ఖచ్చితంగా అనుసరించవద్దనుకుంటున్నారా?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "నవీకరించు",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "ఎన్నుకోండి",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "ఒక ఎన్నికను చేర్చు",
   "poll_button.remove_poll": "ఎన్నికను తొలగించు",
   "privacy.change": "స్టేటస్ గోప్యతను సర్దుబాటు చేయండి",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 33eb315f1..da57280ce 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -63,7 +63,7 @@
   "column.notifications": "การแจ้งเตือน",
   "column.pins": "โพสต์ที่ปักหมุด",
   "column.public": "เส้นเวลาที่ติดต่อกับภายนอก",
-  "column.status": "Toot",
+  "column.status": "โพสต์",
   "column_back_button.label": "ย้อนกลับ",
   "column_header.hide_settings": "ซ่อนการตั้งค่า",
   "column_header.moveLeft_settings": "ย้ายคอลัมน์ไปทางซ้าย",
@@ -111,8 +111,12 @@
   "confirmations.reply.message": "การตอบกลับตอนนี้จะเขียนทับข้อความที่คุณกำลังเขียน คุณแน่ใจหรือไม่ว่าต้องการดำเนินการต่อ?",
   "confirmations.unfollow.confirm": "เลิกติดตาม",
   "confirmations.unfollow.message": "คุณแน่ใจหรือไม่ว่าต้องการเลิกติดตาม {name}?",
-  "directory.federated": "From known fediverse",
-  "directory.local": "From {domain} only",
+  "conversation.delete": "ลบการสนทนา",
+  "conversation.mark_as_read": "ทำเครื่องหมายว่าอ่านแล้ว",
+  "conversation.open": "ดูการสนทนา",
+  "conversation.with": "กับ {names}",
+  "directory.federated": "จากเฟดิเวิร์สที่รู้จัก",
+  "directory.local": "จาก {domain} เท่านั้น",
   "directory.new_arrivals": "New arrivals",
   "directory.recently_active": "Recently active",
   "embed.instructions": "ฝังสถานะนี้ในเว็บไซต์ของคุณโดยคัดลอกโค้ดด้านล่าง",
@@ -170,7 +174,7 @@
   "home.column_settings.basic": "พื้นฐาน",
   "home.column_settings.show_reblogs": "แสดงการดัน",
   "home.column_settings.show_replies": "แสดงการตอบกลับ",
-  "home.column_settings.update_live": "Update in real-time",
+  "home.column_settings.update_live": "อัปเดตตามเวลาจริง",
   "intervals.full.days": "{number, plural, other {# วัน}}",
   "intervals.full.hours": "{number, plural, other {# ชั่วโมง}}",
   "intervals.full.minutes": "{number, plural, other {# นาที}}",
@@ -295,6 +299,7 @@
   "poll.refresh": "รีเฟรช",
   "poll.total_votes": "{count, plural, other {# การลงคะแนน}}",
   "poll.vote": "ลงคะแนน",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "เพิ่มโพล",
   "poll_button.remove_poll": "เอาโพลออก",
   "privacy.change": "ปรับเปลี่ยนความเป็นส่วนตัวของสถานะ",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 2c4d820de..1b5ce07d5 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Şimdi yanıtlarken o an oluşturduğunuz mesajın üzerine yazılır. Devam etmek istediğinize emin misiniz?",
   "confirmations.unfollow.confirm": "Takibi kaldır",
   "confirmations.unfollow.message": "{name}'yi takipten çıkarmak istediğinizden emin misiniz?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "Yalnızca {domain} adresinden",
   "directory.new_arrivals": "Yeni gelenler",
@@ -295,6 +299,7 @@
   "poll.refresh": "Yenile",
   "poll.total_votes": "{count, plural, one {# oy} other {# oy}}",
   "poll.vote": "Oy ver",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Bir anket ekleyin",
   "poll_button.remove_poll": "Anket kaldır",
   "privacy.change": "Gönderi gizliliğini ayarla",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 6ccb20fc6..9a64b857f 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "Поточна відповідь перезапише повідомлення, яке ви зараз пишете. Ви впевнені, що хочете продовжити?",
   "confirmations.unfollow.confirm": "Відписатися",
   "confirmations.unfollow.message": "Ви впевнені, що хочете відписатися від {name}?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "З відомого федесвіту",
   "directory.local": "Тільки з домену {domain}",
   "directory.new_arrivals": "Нові надходження",
@@ -295,6 +299,7 @@
   "poll.refresh": "Оновити",
   "poll.total_votes": "{count, plural, one {# голос} few {# голоси} many {# голосів} other {# голосів}}",
   "poll.vote": "Проголосувати",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Додати опитування",
   "poll_button.remove_poll": "Видалити опитування",
   "privacy.change": "Змінити видимість допису",
diff --git a/app/javascript/mastodon/locales/whitelist_es-AR.json b/app/javascript/mastodon/locales/whitelist_es-AR.json
new file mode 100644
index 000000000..0d4f101c7
--- /dev/null
+++ b/app/javascript/mastodon/locales/whitelist_es-AR.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/app/javascript/mastodon/locales/whitelist_ga.json b/app/javascript/mastodon/locales/whitelist_ga.json
new file mode 100644
index 000000000..0d4f101c7
--- /dev/null
+++ b/app/javascript/mastodon/locales/whitelist_ga.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 2f0373d93..4057fefa9 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "回复此消息将会覆盖当前正在编辑的信息。确定继续吗?",
   "confirmations.unfollow.confirm": "取消关注",
   "confirmations.unfollow.message": "你确定要取消关注 {name} 吗?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "刷新",
   "poll.total_votes": "{count} 票",
   "poll.vote": "投票",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "发起投票",
   "poll_button.remove_poll": "移除投票",
   "privacy.change": "设置嘟文可见范围",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index 0a42aa47f..93439a3a1 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -111,6 +111,10 @@
   "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.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "Refresh",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Vote",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "調整私隱設定",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index 82d7b6db5..b88d1b60d 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -111,6 +111,10 @@
   "confirmations.reply.message": "現在回覆將蓋掉您目前正在撰寫的訊息。是否仍要回覆?",
   "confirmations.unfollow.confirm": "取消關注",
   "confirmations.unfollow.message": "真的要取消關注 {name} 嗎?",
+  "conversation.delete": "Delete conversation",
+  "conversation.mark_as_read": "Mark as read",
+  "conversation.open": "View conversation",
+  "conversation.with": "With {names}",
   "directory.federated": "From known fediverse",
   "directory.local": "From {domain} only",
   "directory.new_arrivals": "New arrivals",
@@ -295,6 +299,7 @@
   "poll.refresh": "重新整理",
   "poll.total_votes": "{count, plural, one {# 個投票} other {# 個投票}}",
   "poll.vote": "投票",
+  "poll.voted": "You voted for this answer",
   "poll_button.add_poll": "建立投票",
   "poll_button.remove_poll": "移除投票",
   "privacy.change": "調整隱私狀態",
diff --git a/app/javascript/mastodon/reducers/blocks.js b/app/javascript/mastodon/reducers/blocks.js
new file mode 100644
index 000000000..1b6507163
--- /dev/null
+++ b/app/javascript/mastodon/reducers/blocks.js
@@ -0,0 +1,22 @@
+import Immutable from 'immutable';
+
+import {
+  BLOCKS_INIT_MODAL,
+} from '../actions/blocks';
+
+const initialState = Immutable.Map({
+  new: Immutable.Map({
+    account_id: null,
+  }),
+});
+
+export default function mutes(state = initialState, action) {
+  switch (action.type) {
+  case BLOCKS_INIT_MODAL:
+    return state.withMutations((state) => {
+      state.setIn(['new', 'account_id'], action.account.get('id'));
+    });
+  default:
+    return state;
+  }
+}
diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js
index 268237846..b5dc81703 100644
--- a/app/javascript/mastodon/reducers/compose.js
+++ b/app/javascript/mastodon/reducers/compose.js
@@ -103,10 +103,13 @@ function clearAll(state) {
   });
 };
 
-function appendMedia(state, media) {
+function appendMedia(state, media, file) {
   const prevSize = state.get('media_attachments').size;
 
   return state.withMutations(map => {
+    if (media.get('type') === 'image') {
+      media = media.set('file', file);
+    }
     map.update('media_attachments', list => list.push(media));
     map.set('is_uploading', false);
     map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
@@ -321,7 +324,7 @@ export default function compose(state = initialState, action) {
   case COMPOSE_UPLOAD_REQUEST:
     return state.set('is_uploading', true);
   case COMPOSE_UPLOAD_SUCCESS:
-    return appendMedia(state, fromJS(action.media));
+    return appendMedia(state, fromJS(action.media), action.file);
   case COMPOSE_UPLOAD_FAIL:
     return state.set('is_uploading', false);
   case COMPOSE_UPLOAD_UNDO:
diff --git a/app/javascript/mastodon/reducers/index.js b/app/javascript/mastodon/reducers/index.js
index 0f4b209d4..b8d608888 100644
--- a/app/javascript/mastodon/reducers/index.js
+++ b/app/javascript/mastodon/reducers/index.js
@@ -15,6 +15,7 @@ import settings from './settings';
 import push_notifications from './push_notifications';
 import status_lists from './status_lists';
 import mutes from './mutes';
+import blocks from './blocks';
 import reports from './reports';
 import contexts from './contexts';
 import compose from './compose';
@@ -51,6 +52,7 @@ const reducers = {
   settings,
   push_notifications,
   mutes,
+  blocks,
   reports,
   contexts,
   compose,
diff --git a/app/javascript/mastodon/reducers/mutes.js b/app/javascript/mastodon/reducers/mutes.js
index a96232dbd..4672e5097 100644
--- a/app/javascript/mastodon/reducers/mutes.js
+++ b/app/javascript/mastodon/reducers/mutes.js
@@ -7,7 +7,6 @@ import {
 
 const initialState = Immutable.Map({
   new: Immutable.Map({
-    isSubmitting: false,
     account: null,
     notifications: true,
   }),
@@ -17,7 +16,6 @@ export default function mutes(state = initialState, action) {
   switch (action.type) {
   case MUTES_INIT_MODAL:
     return state.withMutations((state) => {
-      state.setIn(['new', 'isSubmitting'], false);
       state.setIn(['new', 'account'], action.account);
       state.setIn(['new', 'notifications'], true);
     });
diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js
index 45d3a5c51..6ba80bd6a 100644
--- a/app/javascript/mastodon/reducers/notifications.js
+++ b/app/javascript/mastodon/reducers/notifications.js
@@ -7,6 +7,8 @@ import {
   NOTIFICATIONS_CLEAR,
   NOTIFICATIONS_SCROLL_TOP,
   NOTIFICATIONS_LOAD_PENDING,
+  NOTIFICATIONS_MOUNT,
+  NOTIFICATIONS_UNMOUNT,
 } from '../actions/notifications';
 import {
   ACCOUNT_BLOCK_SUCCESS,
@@ -22,6 +24,7 @@ const initialState = ImmutableMap({
   items: ImmutableList(),
   hasMore: true,
   top: false,
+  mounted: false,
   unread: 0,
   isLoading: false,
 });
@@ -37,7 +40,7 @@ const notificationToMap = notification => ImmutableMap({
 const normalizeNotification = (state, notification, usePendingItems) => {
   const top = state.get('top');
 
-  if (usePendingItems || !top || !state.get('pendingItems').isEmpty()) {
+  if (usePendingItems || !state.get('pendingItems').isEmpty()) {
     return state.update('pendingItems', list => list.unshift(notificationToMap(notification))).update('unread', unread => unread + 1);
   }
 
@@ -63,7 +66,7 @@ const expandNormalizedNotifications = (state, notifications, next, isLoadingRece
 
   return state.withMutations(mutable => {
     if (!items.isEmpty()) {
-      usePendingItems = isLoadingRecent && (usePendingItems || !mutable.get('top') || !mutable.get('pendingItems').isEmpty());
+      usePendingItems = isLoadingRecent && (usePendingItems || !mutable.get('pendingItems').isEmpty());
 
       mutable.update(usePendingItems ? 'pendingItems' : 'items', list => {
         const lastIndex = 1 + list.findLastIndex(
@@ -134,6 +137,10 @@ export default function notifications(state = initialState, action) {
     return action.timeline === 'home' ?
       state.update(action.usePendingItems ? 'pendingItems' : 'items', items => items.first() ? items.unshift(null) : items) :
       state;
+  case NOTIFICATIONS_MOUNT:
+    return state.set('mounted', true);
+  case NOTIFICATIONS_UNMOUNT:
+    return state.set('mounted', false);
   default:
     return state;
   }
diff --git a/app/javascript/mastodon/reducers/timelines.js b/app/javascript/mastodon/reducers/timelines.js
index f3ed2fc59..0d7222e10 100644
--- a/app/javascript/mastodon/reducers/timelines.js
+++ b/app/javascript/mastodon/reducers/timelines.js
@@ -40,7 +40,8 @@ const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, is
     if (timeline.endsWith(':pinned')) {
       mMap.set('items', statuses.map(status => status.get('id')));
     } else if (!statuses.isEmpty()) {
-      usePendingItems = isLoadingRecent && (usePendingItems || !mMap.get('top') || !mMap.get('pendingItems').isEmpty());
+      usePendingItems = isLoadingRecent && (usePendingItems || !mMap.get('pendingItems').isEmpty());
+
       mMap.update(usePendingItems ? 'pendingItems' : 'items', ImmutableList(), oldIds => {
         const newIds = statuses.map(status => status.get('id'));
 
@@ -63,7 +64,7 @@ const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, is
 const updateTimeline = (state, timeline, status, usePendingItems) => {
   const top = state.getIn([timeline, 'top']);
 
-  if (usePendingItems || !top || !state.getIn([timeline, 'pendingItems']).isEmpty()) {
+  if (usePendingItems || !state.getIn([timeline, 'pendingItems']).isEmpty()) {
     if (state.getIn([timeline, 'pendingItems'], ImmutableList()).includes(status.get('id')) || state.getIn([timeline, 'items'], ImmutableList()).includes(status.get('id'))) {
       return state;
     }
diff --git a/app/javascript/mastodon/utils/scrollbar.js b/app/javascript/mastodon/utils/scrollbar.js
new file mode 100644
index 000000000..6f0ee010b
--- /dev/null
+++ b/app/javascript/mastodon/utils/scrollbar.js
@@ -0,0 +1,36 @@
+import { isMobile } from '../is_mobile';
+
+/** @type {number | null} */
+let cachedScrollbarWidth = null;
+
+/**
+ * @return {number}
+ */
+const getActualScrollbarWidth = () => {
+  const outer = document.createElement('div');
+  outer.style.visibility = 'hidden';
+  outer.style.overflow = 'scroll';
+  document.body.appendChild(outer);
+
+  const inner = document.createElement('div');
+  outer.appendChild(inner);
+
+  const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
+  outer.parentNode.removeChild(outer);
+
+  return scrollbarWidth;
+};
+
+/**
+ * @return {number}
+ */
+export const getScrollbarWidth = () => {
+  if (cachedScrollbarWidth !== null) {
+    return cachedScrollbarWidth;
+  }
+
+  const scrollbarWidth = isMobile(window.innerWidth) ? 0 : getActualScrollbarWidth();
+  cachedScrollbarWidth = scrollbarWidth;
+
+  return scrollbarWidth;
+};
diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js
index 9418188a7..1229a7505 100644
--- a/app/javascript/packs/public.js
+++ b/app/javascript/packs/public.js
@@ -110,6 +110,16 @@ function main() {
       this.parentElement.parentElement.nextElementSibling.classList.toggle('hidden');
     });
   });
+
+  delegate(document, '.sidebar__toggle__icon', 'click', () => {
+    const target = document.querySelector('.sidebar ul');
+
+    if (target.style.display === 'block') {
+      target.style.display = 'none';
+    } else {
+      target.style.display = 'block';
+    }
+  });
 }
 
 loadPolyfills().then(main).catch(error => {
diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss
index e7114ed07..45305d696 100644
--- a/app/javascript/styles/mastodon-light/diff.scss
+++ b/app/javascript/styles/mastodon-light/diff.scss
@@ -310,6 +310,7 @@ html {
 .boost-modal,
 .confirmation-modal,
 .mute-modal,
+.block-modal,
 .report-modal,
 .embed-modal,
 .error-modal,
@@ -326,6 +327,7 @@ html {
 .boost-modal__action-bar,
 .confirmation-modal__action-bar,
 .mute-modal__action-bar,
+.block-modal__action-bar,
 .onboarding-modal__paginator,
 .error-modal__footer {
   background: darken($ui-base-color, 6%);
diff --git a/app/javascript/styles/mastodon/_mixins.scss b/app/javascript/styles/mastodon/_mixins.scss
index faaffb30f..68cad0fde 100644
--- a/app/javascript/styles/mastodon/_mixins.scss
+++ b/app/javascript/styles/mastodon/_mixins.scss
@@ -22,24 +22,6 @@
   color: $darker-text-color;
   font-size: 14px;
   margin: 0;
-
-  &::-moz-focus-inner {
-    border: 0;
-  }
-
-  &::-moz-focus-inner,
-  &:focus,
-  &:active {
-    outline: 0 !important;
-  }
-
-  &:focus {
-    background: lighten($ui-base-color, 4%);
-  }
-
-  @media screen and (max-width: 600px) {
-    font-size: 16px;
-  }
 }
 
 @mixin search-popout {
diff --git a/app/javascript/styles/mastodon/about.scss b/app/javascript/styles/mastodon/about.scss
index 61637ce96..1dd8b7954 100644
--- a/app/javascript/styles/mastodon/about.scss
+++ b/app/javascript/styles/mastodon/about.scss
@@ -17,109 +17,102 @@ $small-breakpoint: 960px;
 
 .rich-formatting {
   font-family: $font-sans-serif, sans-serif;
-  font-size: 16px;
+  font-size: 14px;
   font-weight: 400;
-  font-size: 16px;
-  line-height: 30px;
+  line-height: 1.7;
+  word-wrap: break-word;
   color: $darker-text-color;
-  padding-right: 10px;
 
   a {
     color: $highlight-text-color;
     text-decoration: underline;
+
+    &:hover,
+    &:focus,
+    &:active {
+      text-decoration: none;
+    }
   }
 
   p,
   li {
-    font-family: $font-sans-serif, sans-serif;
-    font-size: 16px;
-    font-weight: 400;
-    font-size: 16px;
-    line-height: 30px;
-    margin-bottom: 12px;
     color: $darker-text-color;
+  }
 
-    a {
-      color: $highlight-text-color;
-      text-decoration: underline;
-    }
+  p {
+    margin-top: 0;
+    margin-bottom: .85em;
 
     &:last-child {
       margin-bottom: 0;
     }
   }
 
-  strong,
-  em {
+  strong {
     font-weight: 700;
-    color: lighten($darker-text-color, 10%);
+    color: $secondary-text-color;
   }
 
-  h1 {
-    font-family: $font-display, sans-serif;
-    font-size: 26px;
-    line-height: 30px;
-    font-weight: 500;
-    margin-bottom: 20px;
+  em {
+    font-style: italic;
     color: $secondary-text-color;
+  }
 
-    small {
-      font-family: $font-sans-serif, sans-serif;
-      display: block;
-      font-size: 18px;
-      font-weight: 400;
-      color: lighten($darker-text-color, 10%);
-    }
+  code {
+    font-size: 0.85em;
+    background: darken($ui-base-color, 8%);
+    border-radius: 4px;
+    padding: 0.2em 0.3em;
   }
 
-  h2 {
+  h1,
+  h2,
+  h3,
+  h4,
+  h5,
+  h6 {
     font-family: $font-display, sans-serif;
-    font-size: 22px;
-    line-height: 26px;
+    margin-top: 1.275em;
+    margin-bottom: .85em;
     font-weight: 500;
-    margin-bottom: 20px;
     color: $secondary-text-color;
   }
 
+  h1 {
+    font-size: 2em;
+  }
+
+  h2 {
+    font-size: 1.75em;
+  }
+
   h3 {
-    font-family: $font-display, sans-serif;
-    font-size: 18px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
+    font-size: 1.5em;
   }
 
   h4 {
-    font-family: $font-display, sans-serif;
-    font-size: 16px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
+    font-size: 1.25em;
   }
 
-  h5 {
-    font-family: $font-display, sans-serif;
-    font-size: 14px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
+  h5,
+  h6 {
+    font-size: 1em;
   }
 
-  h6 {
-    font-family: $font-display, sans-serif;
-    font-size: 12px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
+  ul {
+    list-style: disc;
+  }
+
+  ol {
+    list-style: decimal;
   }
 
   ul,
   ol {
-    margin-left: 20px;
+    margin: 0;
+    padding: 0;
+    padding-left: 2em;
+    margin-bottom: 0.85em;
 
     &[type='a'] {
       list-style-type: lower-alpha;
@@ -130,31 +123,63 @@ $small-breakpoint: 960px;
     }
   }
 
-  ul {
-    list-style: disc;
-  }
-
-  ol {
-    list-style: decimal;
-  }
-
-  li > ol,
-  li > ul {
-    margin-top: 6px;
-  }
-
   hr {
     width: 100%;
     height: 0;
     border: 0;
-    border-bottom: 1px solid rgba($ui-base-lighter-color, .6);
-    margin: 20px 0;
+    border-bottom: 1px solid lighten($ui-base-color, 4%);
+    margin: 1.7em 0;
 
     &.spacer {
       height: 1px;
       border: 0;
     }
   }
+
+  table {
+    width: 100%;
+    border-collapse: collapse;
+    break-inside: auto;
+    margin-top: 24px;
+    margin-bottom: 32px;
+
+    thead tr,
+    tbody tr {
+      break-after: auto;
+      break-inside: avoid;
+      border-bottom: 1px solid lighten($ui-base-color, 4%);
+      font-size: 1em;
+      line-height: 1.625;
+      font-weight: 400;
+      text-align: left;
+      color: $darker-text-color;
+    }
+
+    thead tr {
+      border-bottom-width: 2px;
+      line-height: 1.5;
+      font-weight: 500;
+      color: $dark-text-color;
+    }
+
+    th,
+    td {
+      padding: 8px;
+      align-self: start;
+      align-items: start;
+
+      &.nowrap {
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        width: 25%;
+      }
+    }
+  }
+
+  & > :first-child {
+    margin-top: 0;
+  }
 }
 
 .information-board {
@@ -416,7 +441,7 @@ $small-breakpoint: 960px;
   }
 
   &__call-to-action {
-    background: darken($ui-base-color, 4%);
+    background: $ui-base-color;
     border-radius: 4px;
     padding: 25px 40px;
     overflow: hidden;
diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss
index 529ed8666..de95d82bf 100644
--- a/app/javascript/styles/mastodon/admin.scss
+++ b/app/javascript/styles/mastodon/admin.scss
@@ -5,21 +5,66 @@ $content-width: 840px;
 .admin-wrapper {
   display: flex;
   justify-content: center;
-  height: 100%;
+  width: 100%;
+  min-height: 100vh;
 
   .sidebar-wrapper {
-    flex: 1 1 $sidebar-width;
-    height: 100%;
-    background: $ui-base-color;
-    display: flex;
-    justify-content: flex-end;
+    min-height: 100vh;
+    overflow: hidden;
+    pointer-events: none;
+    flex: 1 1 auto;
+
+    &__inner {
+      display: flex;
+      justify-content: flex-end;
+      background: $ui-base-color;
+      height: 100%;
+    }
   }
 
   .sidebar {
     width: $sidebar-width;
-    height: 100%;
     padding: 0;
-    overflow-y: auto;
+    pointer-events: auto;
+
+    &__toggle {
+      display: none;
+      background: lighten($ui-base-color, 8%);
+      height: 48px;
+
+      &__logo {
+        flex: 1 1 auto;
+
+        a {
+          display: inline-block;
+          padding: 15px;
+        }
+
+        svg {
+          fill: $primary-text-color;
+          height: 20px;
+          position: relative;
+          bottom: -2px;
+        }
+      }
+
+      &__icon {
+        display: block;
+        color: $darker-text-color;
+        text-decoration: none;
+        flex: 0 0 auto;
+        font-size: 20px;
+        padding: 15px;
+      }
+
+      a {
+        &:hover,
+        &:focus,
+        &:active {
+          background: lighten($ui-base-color, 12%);
+        }
+      }
+    }
 
     .logo {
       display: block;
@@ -52,6 +97,9 @@ $content-width: 840px;
         transition: all 200ms linear;
         transition-property: color, background-color;
         border-radius: 4px 0 0 4px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
 
         i.fa {
           margin-right: 5px;
@@ -99,12 +147,30 @@ $content-width: 840px;
   }
 
   .content-wrapper {
-    flex: 2 1 $content-width;
-    overflow: auto;
+    box-sizing: border-box;
+    width: 100%;
+    max-width: $content-width;
+    flex: 1 1 auto;
+  }
+
+  @media screen and (max-width: $content-width + $sidebar-width) {
+    .sidebar-wrapper--empty {
+      display: none;
+    }
+
+    .sidebar-wrapper {
+      width: $sidebar-width;
+      flex: 0 0 auto;
+    }
+  }
+
+  @media screen and (max-width: $no-columns-breakpoint) {
+    .sidebar-wrapper {
+      width: 100%;
+    }
   }
 
   .content {
-    max-width: $content-width;
     padding: 20px 15px;
     padding-top: 60px;
     padding-left: 25px;
@@ -123,6 +189,12 @@ $content-width: 840px;
       padding-bottom: 40px;
       border-bottom: 1px solid lighten($ui-base-color, 8%);
       margin-bottom: 40px;
+
+      @media screen and (max-width: $no-columns-breakpoint) {
+        border-bottom: 0;
+        padding-bottom: 0;
+        font-weight: 700;
+      }
     }
 
     h3 {
@@ -147,7 +219,7 @@ $content-width: 840px;
       font-size: 16px;
       color: $secondary-text-color;
       line-height: 28px;
-      font-weight: 400;
+      font-weight: 500;
     }
 
     .fields-group h6 {
@@ -176,7 +248,7 @@ $content-width: 840px;
 
     & > p {
       font-size: 14px;
-      line-height: 18px;
+      line-height: 21px;
       color: $secondary-text-color;
       margin-bottom: 20px;
 
@@ -208,20 +280,42 @@ $content-width: 840px;
 
   @media screen and (max-width: $no-columns-breakpoint) {
     display: block;
-    overflow-y: auto;
-    -webkit-overflow-scrolling: touch;
 
-    .sidebar-wrapper,
-    .content-wrapper {
-      flex: 0 0 auto;
-      height: auto;
-      overflow: initial;
+    .sidebar-wrapper {
+      min-height: 0;
     }
 
     .sidebar {
       width: 100%;
       padding: 0;
       height: auto;
+
+      &__toggle {
+        display: flex;
+      }
+
+      & > ul {
+        display: none;
+      }
+
+      ul a,
+      ul ul a {
+        border-radius: 0;
+        border-bottom: 1px solid lighten($ui-base-color, 4%);
+        transition: none;
+
+        &:hover {
+          transition: none;
+        }
+      }
+
+      ul ul {
+        border-radius: 0;
+      }
+
+      ul .simple-navigation-active-leaf a {
+        border-bottom-color: $ui-highlight-color;
+      }
     }
   }
 }
@@ -233,32 +327,35 @@ hr.spacer {
   height: 1px;
 }
 
-.muted-hint {
-  color: $darker-text-color;
+body,
+.admin-wrapper .content {
+  .muted-hint {
+    color: $darker-text-color;
 
-  a {
-    color: $highlight-text-color;
+    a {
+      color: $highlight-text-color;
+    }
   }
-}
 
-.positive-hint {
-  color: $valid-value-color;
-  font-weight: 500;
-}
+  .positive-hint {
+    color: $valid-value-color;
+    font-weight: 500;
+  }
 
-.negative-hint {
-  color: $error-value-color;
-  font-weight: 500;
-}
+  .negative-hint {
+    color: $error-value-color;
+    font-weight: 500;
+  }
 
-.neutral-hint {
-  color: $dark-text-color;
-  font-weight: 500;
-}
+  .neutral-hint {
+    color: $dark-text-color;
+    font-weight: 500;
+  }
 
-.warning-hint {
-  color: $gold-star;
-  font-weight: 500;
+  .warning-hint {
+    color: $gold-star;
+    font-weight: 500;
+  }
 }
 
 .filters {
@@ -267,10 +364,10 @@ hr.spacer {
 
   .filter-subset {
     flex: 0 0 auto;
-    margin: 0 40px 10px 0;
+    margin: 0 40px 20px 0;
 
     &:last-child {
-      margin-bottom: 20px;
+      margin-bottom: 30px;
     }
 
     ul {
diff --git a/app/javascript/styles/mastodon/basics.scss b/app/javascript/styles/mastodon/basics.scss
index f9332caa3..1f3ef7da2 100644
--- a/app/javascript/styles/mastodon/basics.scss
+++ b/app/javascript/styles/mastodon/basics.scss
@@ -86,9 +86,6 @@ body {
 
   &.admin {
     background: darken($ui-base-color, 4%);
-    position: fixed;
-    width: 100%;
-    height: 100%;
     padding: 0;
   }
 
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index dee3c3439..645a917ee 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -421,6 +421,10 @@
     border: 0;
     outline: 0;
 
+    &::placeholder {
+      color: $dark-text-color;
+    }
+
     &:focus {
       outline: 0;
     }
@@ -1272,14 +1276,28 @@
 
   &-composite {
     @include avatar-radius;
+    border-radius: 50%;
     overflow: hidden;
+    position: relative;
+    cursor: default;
 
     & > div {
-      @include avatar-radius;
       float: left;
       position: relative;
       box-sizing: border-box;
     }
+
+    &__label {
+      display: block;
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      color: $primary-text-color;
+      text-shadow: 1px 1px 2px $base-shadow-color;
+      font-weight: 700;
+      font-size: 15px;
+    }
   }
 }
 
@@ -1511,6 +1529,7 @@ a.account__display-name {
 }
 
 .muted {
+  .status__content,
   .status__content p,
   .status__content a {
     color: $dark-text-color;
@@ -1889,6 +1908,7 @@ a.account__display-name {
       pointer-events: none;
       display: flex;
       justify-content: flex-end;
+      min-width: 285px;
 
       &--start {
         justify-content: flex-start;
@@ -1906,6 +1926,7 @@ a.account__display-name {
       box-sizing: border-box;
       width: 100%;
       max-width: 600px;
+      flex: 0 0 auto;
       display: flex;
       flex-direction: column;
 
@@ -3533,6 +3554,28 @@ a.status-card.compact:hover {
   .column-select {
     &__control {
       @include search-input;
+
+      &::placeholder {
+        color: lighten($darker-text-color, 4%);
+      }
+
+      &::-moz-focus-inner {
+        border: 0;
+      }
+
+      &::-moz-focus-inner,
+      &:focus,
+      &:active {
+        outline: 0 !important;
+      }
+
+      &:focus {
+        background: lighten($ui-base-color, 4%);
+      }
+
+      @media screen and (max-width: 600px) {
+        font-size: 16px;
+      }
     }
 
     &__placeholder {
@@ -4046,6 +4089,28 @@ a.status-card.compact:hover {
   padding-right: 30px;
   line-height: 18px;
   font-size: 16px;
+
+  &::placeholder {
+    color: lighten($darker-text-color, 4%);
+  }
+
+  &::-moz-focus-inner {
+    border: 0;
+  }
+
+  &::-moz-focus-inner,
+  &:focus,
+  &:active {
+    outline: 0 !important;
+  }
+
+  &:focus {
+    background: lighten($ui-base-color, 4%);
+  }
+
+  @media screen and (max-width: 600px) {
+    font-size: 16px;
+  }
 }
 
 .search__icon {
@@ -4468,7 +4533,8 @@ a.status-card.compact:hover {
 .confirmation-modal,
 .report-modal,
 .actions-modal,
-.mute-modal {
+.mute-modal,
+.block-modal {
   background: lighten($ui-secondary-color, 8%);
   color: $inverted-text-color;
   border-radius: 8px;
@@ -4522,7 +4588,8 @@ a.status-card.compact:hover {
 
 .boost-modal__action-bar,
 .confirmation-modal__action-bar,
-.mute-modal__action-bar {
+.mute-modal__action-bar,
+.block-modal__action-bar {
   display: flex;
   justify-content: space-between;
   background: $ui-secondary-color;
@@ -4550,11 +4617,13 @@ a.status-card.compact:hover {
   font-size: 14px;
 }
 
-.mute-modal {
+.mute-modal,
+.block-modal {
   line-height: 24px;
 }
 
-.mute-modal .react-toggle {
+.mute-modal .react-toggle,
+.block-modal .react-toggle {
   vertical-align: middle;
 }
 
@@ -4765,33 +4834,35 @@ a.status-card.compact:hover {
 }
 
 .confirmation-modal__action-bar,
-.mute-modal__action-bar {
-  .confirmation-modal__secondary-button,
-  .confirmation-modal__cancel-button,
-  .mute-modal__cancel-button {
-    background-color: transparent;
-    color: $lighter-text-color;
-    font-size: 14px;
-    font-weight: 500;
-
-    &:hover,
-    &:focus,
-    &:active {
-      color: darken($lighter-text-color, 4%);
-    }
-  }
-
+.mute-modal__action-bar,
+.block-modal__action-bar {
   .confirmation-modal__secondary-button {
     flex-shrink: 1;
   }
 }
 
+.confirmation-modal__secondary-button,
+.confirmation-modal__cancel-button,
+.mute-modal__cancel-button,
+.block-modal__cancel-button {
+  background-color: transparent;
+  color: $lighter-text-color;
+  font-size: 14px;
+  font-weight: 500;
+
+  &:hover,
+  &:focus,
+  &:active {
+    color: darken($lighter-text-color, 4%);
+  }
+}
+
 .confirmation-modal__container,
 .mute-modal__container,
+.block-modal__container,
 .report-modal__target {
   padding: 30px;
   font-size: 16px;
-  text-align: center;
 
   strong {
     font-weight: 500;
@@ -4804,6 +4875,31 @@ a.status-card.compact:hover {
   }
 }
 
+.confirmation-modal__container,
+.report-modal__target {
+  text-align: center;
+}
+
+.block-modal,
+.mute-modal {
+  &__explanation {
+    margin-top: 20px;
+  }
+
+  .setting-toggle {
+    margin-top: 20px;
+    margin-bottom: 24px;
+    display: flex;
+    align-items: center;
+
+    &__label {
+      color: $inverted-text-color;
+      margin: 0;
+      margin-left: 8px;
+    }
+  }
+}
+
 .report-modal__target {
   padding: 15px;
 
@@ -6333,48 +6429,63 @@ noscript {
   }
 }
 
-.layout-toggle {
+.conversation {
   display: flex;
+  border-bottom: 1px solid lighten($ui-base-color, 8%);
   padding: 5px;
+  padding-bottom: 0;
 
-  button {
-    box-sizing: border-box;
-    flex: 0 0 50%;
-    background: transparent;
-    padding: 5px;
-    border: 0;
-    position: relative;
+  &:focus {
+    background: lighten($ui-base-color, 2%);
+    outline: 0;
+  }
 
-    &:hover,
-    &:focus,
-    &:active {
-      svg path:first-child {
-        fill: lighten($ui-base-color, 16%);
-      }
-    }
+  &__avatar {
+    flex: 0 0 auto;
+    padding: 10px;
+    padding-top: 12px;
   }
 
-  svg {
-    width: 100%;
-    height: auto;
+  &__content {
+    flex: 1 1 auto;
+    padding: 10px 5px;
+    padding-right: 15px;
+    word-break: break-all;
+    overflow: hidden;
 
-    path:first-child {
-      fill: lighten($ui-base-color, 12%);
+    &__info {
+      overflow: hidden;
+      display: flex;
+      flex-direction: row-reverse;
+      justify-content: space-between;
     }
 
-    path:last-child {
-      fill: darken($ui-base-color, 14%);
+    &__relative-time {
+      font-size: 15px;
+      color: $darker-text-color;
+      padding-left: 15px;
     }
-  }
 
-  &__active {
-    color: $ui-highlight-color;
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    transform: translate(-50%, -50%);
-    background: lighten($ui-base-color, 12%);
-    border-radius: 50%;
-    padding: 0.35rem;
+    &__names {
+      color: $darker-text-color;
+      font-size: 15px;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      margin-bottom: 4px;
+      flex-basis: 170px;
+      flex-shrink: 1000;
+
+      a {
+        color: $primary-text-color;
+        text-decoration: none;
+
+        &:hover,
+        &:focus,
+        &:active {
+          text-decoration: underline;
+        }
+      }
+    }
   }
 }
diff --git a/app/javascript/styles/mastodon/containers.scss b/app/javascript/styles/mastodon/containers.scss
index aa45c0174..2d1bf1abd 100644
--- a/app/javascript/styles/mastodon/containers.scss
+++ b/app/javascript/styles/mastodon/containers.scss
@@ -141,6 +141,63 @@
     grid-row: 3;
   }
 
+  @media screen and (max-width: $no-gap-breakpoint) {
+    grid-gap: 0;
+    grid-template-columns: minmax(0, 100%);
+
+    .column-0 {
+      grid-column: 1;
+    }
+
+    .column-1 {
+      grid-column: 1;
+      grid-row: 3;
+    }
+
+    .column-2 {
+      grid-column: 1;
+      grid-row: 2;
+    }
+
+    .column-3 {
+      grid-column: 1;
+      grid-row: 4;
+    }
+  }
+}
+
+.grid-4 {
+  display: grid;
+  grid-gap: 10px;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  grid-auto-columns: 25%;
+  grid-auto-rows: max-content;
+
+  .column-0 {
+    grid-column: 1 / 5;
+    grid-row: 1;
+  }
+
+  .column-1 {
+    grid-column: 1 / 4;
+    grid-row: 2;
+  }
+
+  .column-2 {
+    grid-column: 4;
+    grid-row: 2;
+  }
+
+  .column-3 {
+    grid-column: 2 / 5;
+    grid-row: 3;
+  }
+
+  .column-4 {
+    grid-column: 1;
+    grid-row: 3;
+  }
+
   .landing-page__call-to-action {
     min-height: 100%;
   }
@@ -190,6 +247,11 @@
 
     .column-3 {
       grid-column: 1;
+      grid-row: 5;
+    }
+
+    .column-4 {
+      grid-column: 1;
       grid-row: 4;
     }
   }
diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss
index 16352340b..b729d912e 100644
--- a/app/javascript/styles/mastodon/forms.scss
+++ b/app/javascript/styles/mastodon/forms.scss
@@ -254,6 +254,10 @@ code {
       &-6 {
         max-width: 50%;
       }
+
+      .actions {
+        margin-top: 27px;
+      }
     }
 
     .fields-group:last-child,
@@ -334,6 +338,10 @@ code {
     border-radius: 4px;
     padding: 10px;
 
+    &::placeholder {
+      color: lighten($darker-text-color, 4%);
+    }
+
     &:invalid {
       box-shadow: none;
     }
diff --git a/app/javascript/styles/mastodon/polls.scss b/app/javascript/styles/mastodon/polls.scss
index e80220f27..f59a9d693 100644
--- a/app/javascript/styles/mastodon/polls.scss
+++ b/app/javascript/styles/mastodon/polls.scss
@@ -95,13 +95,19 @@
 
   &__number {
     display: inline-block;
-    width: 36px;
+    width: 52px;
     font-weight: 700;
     padding: 0 10px;
+    padding-left: 8px;
     text-align: right;
     margin-top: auto;
     margin-bottom: auto;
-    flex: 0 0 36px;
+    flex: 0 0 52px;
+  }
+
+  &__vote__mark {
+    float: left;
+    line-height: 18px;
   }
 
   &__footer {
diff --git a/app/javascript/styles/mastodon/tables.scss b/app/javascript/styles/mastodon/tables.scss
index d6403986f..5a6e10aa4 100644
--- a/app/javascript/styles/mastodon/tables.scss
+++ b/app/javascript/styles/mastodon/tables.scss
@@ -292,70 +292,3 @@ a.table-action-link {
     }
   }
 }
-
-.blocks-table {
-  width: 100%;
-  max-width: 100%;
-  border-spacing: 0;
-  border-collapse: collapse;
-  table-layout: fixed;
-  border: 1px solid darken($ui-base-color, 8%);
-
-  thead {
-    border: 1px solid darken($ui-base-color, 8%);
-    background: darken($ui-base-color, 4%);
-    font-weight: 500;
-
-    th.severity-column {
-      width: 120px;
-    }
-
-    th.button-column {
-      width: 23px;
-    }
-  }
-
-  tbody > tr {
-    border: 1px solid darken($ui-base-color, 8%);
-    border-bottom: 0;
-    background: darken($ui-base-color, 4%);
-
-    &:hover {
-      background: darken($ui-base-color, 2%);
-    }
-
-    &.even {
-      background: $ui-base-color;
-
-      &:hover {
-        background: lighten($ui-base-color, 2%);
-      }
-    }
-
-    &.rationale {
-      background: lighten($ui-base-color, 4%);
-      border-top: 0;
-
-      &:hover {
-        background: lighten($ui-base-color, 6%);
-      }
-
-      &.hidden {
-        display: none;
-      }
-    }
-
-    td:first-child {
-      overflow: hidden;
-      text-overflow: ellipsis;
-    }
-  }
-
-  th,
-  td {
-    padding: 8px;
-    line-height: 18px;
-    vertical-align: top;
-    text-align: left;
-  }
-}
diff --git a/app/javascript/styles/mastodon/widgets.scss b/app/javascript/styles/mastodon/widgets.scss
index 04beb869c..ca050a8d9 100644
--- a/app/javascript/styles/mastodon/widgets.scss
+++ b/app/javascript/styles/mastodon/widgets.scss
@@ -128,41 +128,43 @@
   margin-bottom: 10px;
 }
 
-.contact-widget,
-.landing-page__information.contact-widget {
-  box-sizing: border-box;
-  padding: 20px;
-  min-height: 100%;
-  border-radius: 4px;
-  background: $ui-base-color;
-  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
-}
-
 .contact-widget {
+  min-height: 100%;
   font-size: 15px;
   color: $darker-text-color;
   line-height: 20px;
   word-wrap: break-word;
   font-weight: 400;
+  padding: 0;
 
-  strong {
-    font-weight: 500;
+  h4 {
+    padding: 10px;
+    text-transform: uppercase;
+    font-weight: 700;
+    font-size: 13px;
+    color: $darker-text-color;
   }
 
-  p {
-    margin-bottom: 10px;
-
-    &:last-child {
-      margin-bottom: 0;
-    }
+  .account {
+    border-bottom: 0;
+    padding: 10px 0;
+    padding-top: 5px;
   }
 
-  &__mail {
-    margin-top: 10px;
+  & > a {
+    display: inline-block;
+    padding: 10px;
+    padding-top: 0;
+    color: $darker-text-color;
+    text-decoration: none;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
 
-    a {
-      color: $primary-text-color;
-      text-decoration: none;
+    &:hover,
+    &:focus,
+    &:active {
+      text-decoration: underline;
     }
   }
 }
@@ -562,3 +564,38 @@ $fluid-breakpoint: $maximum-width + 20px;
     }
   }
 }
+
+.table-of-contents {
+  background: darken($ui-base-color, 4%);
+  min-height: 100%;
+  font-size: 14px;
+  border-radius: 4px;
+
+  li a {
+    display: block;
+    font-weight: 500;
+    padding: 15px;
+    overflow: hidden;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    text-decoration: none;
+    color: $primary-text-color;
+    border-bottom: 1px solid lighten($ui-base-color, 4%);
+
+    &:hover,
+    &:focus,
+    &:active {
+      text-decoration: underline;
+    }
+  }
+
+  li:last-child a {
+    border-bottom: 0;
+  }
+
+  li ul {
+    padding-left: 20px;
+    border-bottom: 1px solid lighten($ui-base-color, 4%);
+  }
+}
diff --git a/app/lib/activity_tracker.rb b/app/lib/activity_tracker.rb
index ae3c11b6a..81303b715 100644
--- a/app/lib/activity_tracker.rb
+++ b/app/lib/activity_tracker.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class ActivityTracker
-  EXPIRE_AFTER = 90.days.seconds
+  EXPIRE_AFTER = 6.months.seconds
 
   class << self
     include Redisable
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb
index e69193b71..76bf9b2e5 100644
--- a/app/lib/activitypub/activity/create.rb
+++ b/app/lib/activitypub/activity/create.rb
@@ -232,25 +232,40 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
       items    = @object['oneOf']
     end
 
+    voters_count = @object['votersCount']
+
     @account.polls.new(
       multiple: multiple,
       expires_at: expires_at,
       options: items.map { |item| item['name'].presence || item['content'] }.compact,
-      cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 }
+      cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 },
+      voters_count: voters_count
     )
   end
 
   def poll_vote?
     return false if replied_to_status.nil? || replied_to_status.preloadable_poll.nil? || !replied_to_status.local? || !replied_to_status.preloadable_poll.options.include?(@object['name'])
 
-    unless replied_to_status.preloadable_poll.expired?
-      replied_to_status.preloadable_poll.votes.create!(account: @account, choice: replied_to_status.preloadable_poll.options.index(@object['name']), uri: @object['id'])
-      ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, replied_to_status.id) unless replied_to_status.preloadable_poll.hide_totals?
-    end
+    poll_vote! unless replied_to_status.preloadable_poll.expired?
 
     true
   end
 
+  def poll_vote!
+    poll = replied_to_status.preloadable_poll
+    already_voted = true
+    RedisLock.acquire(poll_lock_options) do |lock|
+      if lock.acquired?
+        already_voted = poll.votes.where(account: @account).exists?
+        poll.votes.create!(account: @account, choice: poll.options.index(@object['name']), uri: @object['id'])
+      else
+        raise Mastodon::RaceConditionError
+      end
+    end
+    increment_voters_count! unless already_voted
+    ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, replied_to_status.id) unless replied_to_status.preloadable_poll.hide_totals?
+  end
+
   def resolve_thread(status)
     return unless status.reply? && status.thread.nil? && Request.valid_url?(in_reply_to_uri)
     ThreadResolveWorker.perform_async(status.id, in_reply_to_uri)
@@ -416,7 +431,22 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
     ActivityPub::RawDistributionWorker.perform_async(Oj.dump(@json), replied_to_status.account_id, [@account.preferred_inbox_url])
   end
 
+  def increment_voters_count!
+    poll = replied_to_status.preloadable_poll
+    unless poll.voters_count.nil?
+      poll.voters_count = poll.voters_count + 1
+      poll.save
+    end
+  rescue ActiveRecord::StaleObjectError
+    poll.reload
+    retry
+  end
+
   def lock_options
     { redis: Redis.current, key: "create:#{@object['id']}" }
   end
+
+  def poll_lock_options
+    { redis: Redis.current, key: "vote:#{replied_to_status.poll_id}:#{@account.id}" }
+  end
 end
diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb
index 28f1da19f..ec92f4255 100644
--- a/app/lib/activitypub/activity/follow.rb
+++ b/app/lib/activitypub/activity/follow.rb
@@ -21,7 +21,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
 
     follow_request = FollowRequest.create!(account: @account, target_account: target_account, uri: @json['id'])
 
-    if target_account.locked?
+    if target_account.locked? || @account.silenced?
       NotifyService.new.call(target_account, follow_request)
     else
       AuthorizeFollowService.new.call(@account, target_account)
diff --git a/app/lib/activitypub/activity/move.rb b/app/lib/activitypub/activity/move.rb
index 6c6a2b967..12bb82d25 100644
--- a/app/lib/activitypub/activity/move.rb
+++ b/app/lib/activitypub/activity/move.rb
@@ -19,11 +19,7 @@ class ActivityPub::Activity::Move < ActivityPub::Activity
     origin_account.update(moved_to_account: target_account)
 
     # Initiate a re-follow for each follower
-    origin_account.followers.local.select(:id).find_in_batches do |follower_accounts|
-      UnfollowFollowWorker.push_bulk(follower_accounts.map(&:id)) do |follower_account_id|
-        [follower_account_id, origin_account.id, target_account.id]
-      end
-    end
+    MoveWorker.perform_async(origin_account.id, target_account.id)
   end
 
   private
diff --git a/app/lib/activitypub/adapter.rb b/app/lib/activitypub/adapter.rb
index cb2ac72d4..2a8f72333 100644
--- a/app/lib/activitypub/adapter.rb
+++ b/app/lib/activitypub/adapter.rb
@@ -21,6 +21,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
     identity_proof: { 'toot' => 'http://joinmastodon.org/ns#', 'IdentityProof' => 'toot:IdentityProof' },
     blurhash: { 'toot' => 'http://joinmastodon.org/ns#', 'blurhash' => 'toot:blurhash' },
     discoverable: { 'toot' => 'http://joinmastodon.org/ns#', 'discoverable' => 'toot:discoverable' },
+    voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' },
   }.freeze
 
   def self.default_key_transform
diff --git a/app/lib/nodeinfo/adapter.rb b/app/lib/nodeinfo/adapter.rb
new file mode 100644
index 000000000..1b48dcb98
--- /dev/null
+++ b/app/lib/nodeinfo/adapter.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class NodeInfo::Adapter < ActiveModelSerializers::Adapter::Attributes
+  def self.default_key_transform
+    :camel_lower
+  end
+end
diff --git a/app/lib/toc_generator.rb b/app/lib/toc_generator.rb
new file mode 100644
index 000000000..0c8f766ca
--- /dev/null
+++ b/app/lib/toc_generator.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+class TOCGenerator
+  TARGET_ELEMENTS = %w(h1 h2 h3 h4 h5 h6).freeze
+  LISTED_ELEMENTS = %w(h2 h3).freeze
+
+  class Section
+    attr_accessor :depth, :title, :children, :anchor
+
+    def initialize(depth, title, anchor)
+      @depth    = depth
+      @title    = title
+      @children = []
+      @anchor   = anchor
+    end
+
+    delegate :<<, to: :children
+  end
+
+  def initialize(source_html)
+    @source_html = source_html
+    @processed   = false
+    @target_html = ''
+    @headers     = []
+    @slugs       = Hash.new { |h, k| h[k] = 0 }
+  end
+
+  def html
+    parse_and_transform unless @processed
+    @target_html
+  end
+
+  def toc
+    parse_and_transform unless @processed
+    @headers
+  end
+
+  private
+
+  def parse_and_transform
+    return if @source_html.blank?
+
+    parsed_html = Nokogiri::HTML.fragment(@source_html)
+
+    parsed_html.traverse do |node|
+      next unless TARGET_ELEMENTS.include?(node.name)
+
+      anchor = node['id'] || node.text.parameterize.presence || 'sec'
+      @slugs[anchor] += 1
+      anchor = "#{anchor}-#{@slugs[anchor]}" if @slugs[anchor] > 1
+
+      node['id'] = anchor
+
+      next unless LISTED_ELEMENTS.include?(node.name)
+
+      depth          = node.name[1..-1]
+      latest_section = @headers.last
+
+      if latest_section.nil? || latest_section.depth >= depth
+        @headers << Section.new(depth, node.text, anchor)
+      else
+        latest_section << Section.new(depth, node.text, anchor)
+      end
+    end
+
+    @target_html = parsed_html.to_s
+    @processed   = true
+  end
+end
diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb
index b41004acc..6b81f6873 100644
--- a/app/mailers/user_mailer.rb
+++ b/app/mailers/user_mailer.rb
@@ -57,6 +57,39 @@ class UserMailer < Devise::Mailer
     end
   end
 
+  def two_factor_enabled(user, **)
+    @resource = user
+    @instance = Rails.configuration.x.local_domain
+
+    return if @resource.disabled?
+
+    I18n.with_locale(@resource.locale || I18n.default_locale) do
+      mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_enabled.subject')
+    end
+  end
+
+  def two_factor_disabled(user, **)
+    @resource = user
+    @instance = Rails.configuration.x.local_domain
+
+    return if @resource.disabled?
+
+    I18n.with_locale(@resource.locale || I18n.default_locale) do
+      mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_disabled.subject')
+    end
+  end
+
+  def two_factor_recovery_codes_changed(user, **)
+    @resource = user
+    @instance = Rails.configuration.x.local_domain
+
+    return if @resource.disabled?
+
+    I18n.with_locale(@resource.locale || I18n.default_locale) do
+      mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_recovery_codes_changed.subject')
+    end
+  end
+
   def welcome(user)
     @resource = user
     @instance = Rails.configuration.x.local_domain
diff --git a/app/models/account_alias.rb b/app/models/account_alias.rb
new file mode 100644
index 000000000..66f8ce409
--- /dev/null
+++ b/app/models/account_alias.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+# == Schema Information
+#
+# Table name: account_aliases
+#
+#  id         :bigint(8)        not null, primary key
+#  account_id :bigint(8)
+#  acct       :string           default(""), not null
+#  uri        :string           default(""), not null
+#  created_at :datetime         not null
+#  updated_at :datetime         not null
+#
+
+class AccountAlias < ApplicationRecord
+  belongs_to :account
+
+  validates :acct, presence: true, domain: { acct: true }
+  validates :uri, presence: true
+  validates :uri, uniqueness: { scope: :account_id }
+
+  before_validation :set_uri
+  after_create :add_to_account
+  after_destroy :remove_from_account
+
+  def acct=(val)
+    val = val.to_s.strip
+    super(val.start_with?('@') ? val[1..-1] : val)
+  end
+
+  private
+
+  def set_uri
+    target_account = ResolveAccountService.new.call(acct)
+    self.uri       = ActivityPub::TagManager.instance.uri_for(target_account) unless target_account.nil?
+  rescue Goldfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error
+    # Validation will take care of it
+  end
+
+  def add_to_account
+    account.update(also_known_as: account.also_known_as + [uri])
+  end
+
+  def remove_from_account
+    account.update(also_known_as: account.also_known_as.reject { |x| x == uri })
+  end
+end
diff --git a/app/models/account_migration.rb b/app/models/account_migration.rb
new file mode 100644
index 000000000..681b5b2cd
--- /dev/null
+++ b/app/models/account_migration.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+# == Schema Information
+#
+# Table name: account_migrations
+#
+#  id                :bigint(8)        not null, primary key
+#  account_id        :bigint(8)
+#  acct              :string           default(""), not null
+#  followers_count   :bigint(8)        default(0), not null
+#  target_account_id :bigint(8)
+#  created_at        :datetime         not null
+#  updated_at        :datetime         not null
+#
+
+class AccountMigration < ApplicationRecord
+  COOLDOWN_PERIOD = 30.days.freeze
+
+  belongs_to :account
+  belongs_to :target_account, class_name: 'Account'
+
+  before_validation :set_target_account
+  before_validation :set_followers_count
+
+  validates :acct, presence: true, domain: { acct: true }
+  validate :validate_migration_cooldown
+  validate :validate_target_account
+
+  scope :within_cooldown, ->(now = Time.now.utc) { where(arel_table[:created_at].gteq(now - COOLDOWN_PERIOD)) }
+
+  attr_accessor :current_password, :current_username
+
+  def save_with_challenge(current_user)
+    if current_user.encrypted_password.present?
+      errors.add(:current_password, :invalid) unless current_user.valid_password?(current_password)
+    else
+      errors.add(:current_username, :invalid) unless account.username == current_username
+    end
+
+    return false unless errors.empty?
+
+    save
+  end
+
+  def cooldown_at
+    created_at + COOLDOWN_PERIOD
+  end
+
+  def acct=(val)
+    super(val.to_s.strip.gsub(/\A@/, ''))
+  end
+
+  private
+
+  def set_target_account
+    self.target_account = ResolveAccountService.new.call(acct)
+  rescue Goldfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error
+    # Validation will take care of it
+  end
+
+  def set_followers_count
+    self.followers_count = account.followers_count
+  end
+
+  def validate_target_account
+    if target_account.nil?
+      errors.add(:acct, I18n.t('migrations.errors.not_found'))
+    else
+      errors.add(:acct, I18n.t('migrations.errors.missing_also_known_as')) unless target_account.also_known_as.include?(ActivityPub::TagManager.instance.uri_for(account))
+      errors.add(:acct, I18n.t('migrations.errors.already_moved')) if account.moved_to_account_id.present? && account.moved_to_account_id == target_account.id
+      errors.add(:acct, I18n.t('migrations.errors.move_to_self')) if account.id == target_account.id
+    end
+  end
+
+  def validate_migration_cooldown
+    errors.add(:base, I18n.t('migrations.errors.on_cooldown')) if account.migrations.within_cooldown.exists?
+  end
+end
diff --git a/app/models/concerns/account_associations.rb b/app/models/concerns/account_associations.rb
index f76cf305f..499edbf4e 100644
--- a/app/models/concerns/account_associations.rb
+++ b/app/models/concerns/account_associations.rb
@@ -53,6 +53,8 @@ module AccountAssociations
 
     # Account migrations
     belongs_to :moved_to_account, class_name: 'Account', optional: true
+    has_many :migrations, class_name: 'AccountMigration', dependent: :destroy, inverse_of: :account
+    has_many :aliases, class_name: 'AccountAlias', dependent: :destroy, inverse_of: :account
 
     # Hashtags
     has_and_belongs_to_many :tags
diff --git a/app/models/concerns/ldap_authenticable.rb b/app/models/concerns/ldap_authenticable.rb
index 84ff84c4b..117993947 100644
--- a/app/models/concerns/ldap_authenticable.rb
+++ b/app/models/concerns/ldap_authenticable.rb
@@ -3,24 +3,50 @@
 module LdapAuthenticable
   extend ActiveSupport::Concern
 
-  def ldap_setup(_attributes)
-    self.confirmed_at = Time.now.utc
-    self.admin        = false
-    self.external     = true
+  class_methods do
+    def authenticate_with_ldap(params = {})
+      ldap   = Net::LDAP.new(ldap_options)
+      filter = format(Devise.ldap_search_filter, uid: Devise.ldap_uid, email: params[:email])
 
-    save!
-  end
+      if (user_info = ldap.bind_as(base: Devise.ldap_base, filter: filter, password: params[:password]))
+        ldap_get_user(user_info.first)
+      end
+    end
 
-  class_methods do
     def ldap_get_user(attributes = {})
       resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first })
 
       if resource.blank?
-        resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first })
-        resource.ldap_setup(attributes)
+        resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first }, admin: false, external: true, confirmed_at: Time.now.utc)
+        resource.save!
       end
 
       resource
     end
+
+    def ldap_options
+      opts = {
+        host: Devise.ldap_host,
+        port: Devise.ldap_port,
+        base: Devise.ldap_base,
+
+        auth: {
+          method: :simple,
+          username: Devise.ldap_bind_dn,
+          password: Devise.ldap_password,
+        },
+
+        connect_timeout: 10,
+      }
+
+      if [:simple_tls, :start_tls].include?(Devise.ldap_method)
+        opts[:encryption] = {
+          method: Devise.ldap_method,
+          tls_options: OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.tap { |options| options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if Devise.ldap_tls_no_verify },
+        }
+      end
+
+      opts
+    end
   end
 end
diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb
index 4383cbd05..4e865b850 100644
--- a/app/models/domain_block.rb
+++ b/app/models/domain_block.rb
@@ -26,6 +26,7 @@ class DomainBlock < ApplicationRecord
 
   scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
   scope :with_user_facing_limitations, -> { where(severity: [:silence, :suspend]).or(where(reject_media: true)) }
+  scope :by_severity, -> { order(Arel.sql('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), reject_media, domain')) }
 
   class << self
     def suspend?(domain)
diff --git a/app/models/form/challenge.rb b/app/models/form/challenge.rb
new file mode 100644
index 000000000..40c99649c
--- /dev/null
+++ b/app/models/form/challenge.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+class Form::Challenge
+  include ActiveModel::Model
+
+  attr_accessor :current_password, :current_username,
+                :return_to
+end
diff --git a/app/models/form/migration.rb b/app/models/form/migration.rb
deleted file mode 100644
index c2a8655e1..000000000
--- a/app/models/form/migration.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-class Form::Migration
-  include ActiveModel::Validations
-
-  attr_accessor :acct, :account
-
-  def initialize(attrs = {})
-    @account = attrs[:account]
-    @acct    = attrs[:account].acct unless @account.nil?
-    @acct    = attrs[:acct].gsub(/\A@/, '').strip unless attrs[:acct].nil?
-  end
-
-  def valid?
-    return false unless super
-    set_account
-    errors.empty?
-  end
-
-  private
-
-  def set_account
-    self.account = (ResolveAccountService.new.call(acct) if account.nil? && acct.present?)
-  end
-end
diff --git a/app/models/form/redirect.rb b/app/models/form/redirect.rb
new file mode 100644
index 000000000..a7961f8e8
--- /dev/null
+++ b/app/models/form/redirect.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+class Form::Redirect
+  include ActiveModel::Model
+
+  attr_accessor :account, :target_account, :current_password,
+                :current_username
+
+  attr_reader :acct
+
+  validates :acct, presence: true, domain: { acct: true }
+  validate :validate_target_account
+
+  def valid_with_challenge?(current_user)
+    if current_user.encrypted_password.present?
+      errors.add(:current_password, :invalid) unless current_user.valid_password?(current_password)
+    else
+      errors.add(:current_username, :invalid) unless account.username == current_username
+    end
+
+    return false unless errors.empty?
+
+    set_target_account
+    valid?
+  end
+
+  def acct=(val)
+    @acct = val.to_s.strip.gsub(/\A@/, '')
+  end
+
+  private
+
+  def set_target_account
+    @target_account = ResolveAccountService.new.call(acct)
+  rescue Goldfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error
+    # Validation will take care of it
+  end
+
+  def validate_target_account
+    if target_account.nil?
+      errors.add(:acct, I18n.t('migrations.errors.not_found'))
+    else
+      errors.add(:acct, I18n.t('migrations.errors.already_moved')) if account.moved_to_account_id.present? && account.moved_to_account_id == target_account.id
+      errors.add(:acct, I18n.t('migrations.errors.move_to_self')) if account.id == target_account.id
+    end
+  end
+end
diff --git a/app/models/poll.rb b/app/models/poll.rb
index 8f72c7b11..5427368fd 100644
--- a/app/models/poll.rb
+++ b/app/models/poll.rb
@@ -16,6 +16,7 @@
 #  created_at      :datetime         not null
 #  updated_at      :datetime         not null
 #  lock_version    :integer          default(0), not null
+#  voters_count    :bigint(8)
 #
 
 class Poll < ApplicationRecord
@@ -54,6 +55,10 @@ class Poll < ApplicationRecord
     account.id == account_id || votes.where(account: account).exists?
   end
 
+  def own_votes(account)
+    votes.where(account: account).pluck(:choice)
+  end
+
   delegate :local?, to: :account
 
   def remote?
diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb
index 9d6c1938a..4e89fbf85 100644
--- a/app/models/preview_card.rb
+++ b/app/models/preview_card.rb
@@ -47,6 +47,10 @@ class PreviewCard < ApplicationRecord
 
   before_save :extract_dimensions, if: :link?
 
+  def missing_image?
+    width.present? && height.present? && image_file_name.blank?
+  end
+
   def save_with_optional_image!
     save!
   rescue ActiveRecord::RecordInvalid
diff --git a/app/models/relay.rb b/app/models/relay.rb
index 6934a5c62..8c8a97db3 100644
--- a/app/models/relay.rb
+++ b/app/models/relay.rb
@@ -12,8 +12,6 @@
 #
 
 class Relay < ApplicationRecord
-  PRESET_RELAY = 'https://relay.joinmastodon.org/inbox'
-
   validates :inbox_url, presence: true, uniqueness: true, url: true, if: :will_save_change_to_inbox_url?
 
   enum state: [:idle, :pending, :accepted, :rejected]
@@ -74,7 +72,6 @@ class Relay < ApplicationRecord
   end
 
   def ensure_disabled
-    return unless enabled?
-    disable!
+    disable! if enabled?
   end
 end
diff --git a/app/models/remote_follow.rb b/app/models/remote_follow.rb
index 52dd3f67b..5ea535287 100644
--- a/app/models/remote_follow.rb
+++ b/app/models/remote_follow.rb
@@ -49,7 +49,7 @@ class RemoteFollow
   end
 
   def fetch_template!
-    return missing_resource if acct.blank?
+    return missing_resource_error if acct.blank?
 
     _, domain = acct.split('@')
 
diff --git a/app/models/status.rb b/app/models/status.rb
index b0f610aa2..202434db3 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -360,7 +360,7 @@ class Status < ApplicationRecord
     end
 
     def reblogs_map(status_ids, account_id)
-      select('reblog_of_id').where(reblog_of_id: status_ids).where(account_id: account_id).reorder(nil).each_with_object({}) { |s, h| h[s.reblog_of_id] = true }
+      unscoped.select('reblog_of_id').where(reblog_of_id: status_ids).where(account_id: account_id).each_with_object({}) { |s, h| h[s.reblog_of_id] = true }
     end
 
     def mutes_map(conversation_ids, account_id)
diff --git a/app/models/tag.rb b/app/models/tag.rb
index b52b9bc9f..9aca3983f 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -124,16 +124,15 @@ class Tag < ApplicationRecord
       end
     end
 
-    def search_for(term, limit = 5, offset = 0)
+    def search_for(term, limit = 5, offset = 0, options = {})
       normalized_term = normalize(term.strip).mb_chars.downcase.to_s
       pattern         = sanitize_sql_like(normalized_term) + '%'
+      query           = Tag.listable.where(arel_table[:name].lower.matches(pattern))
+      query           = query.where(arel_table[:name].lower.eq(normalized_term).or(arel_table[:reviewed_at].not_eq(nil))) if options[:exclude_unreviewed]
 
-      Tag.listable
-         .where(arel_table[:name].lower.matches(pattern))
-         .where(arel_table[:name].lower.eq(normalized_term).or(arel_table[:reviewed_at].not_eq(nil)))
-         .order(Arel.sql('length(name) ASC, name ASC'))
-         .limit(limit)
-         .offset(offset)
+      query.order(Arel.sql('length(name) ASC, name ASC'))
+           .limit(limit)
+           .offset(offset)
     end
 
     def find_normalized(name)
diff --git a/app/models/user.rb b/app/models/user.rb
index 792246b1d..1556f677d 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -169,7 +169,7 @@ class User < ApplicationRecord
   end
 
   def functional?
-    confirmed? && approved? && !disabled? && !account.suspended?
+    confirmed? && approved? && !disabled? && !account.suspended? && account.moved_to_account_id.nil?
   end
 
   def unconfirmed_or_pending?
@@ -265,17 +265,20 @@ class User < ApplicationRecord
   end
 
   def password_required?
-    return false if Devise.pam_authentication || Devise.ldap_authentication
+    return false if external?
+
     super
   end
 
   def send_reset_password_instructions
-    return false if encrypted_password.blank? && (Devise.pam_authentication || Devise.ldap_authentication)
+    return false if encrypted_password.blank?
+
     super
   end
 
   def reset_password!(new_password, new_password_confirmation)
-    return false if encrypted_password.blank? && (Devise.pam_authentication || Devise.ldap_authentication)
+    return false if encrypted_password.blank?
+
     super
   end
 
diff --git a/app/models/web/push_subscription.rb b/app/models/web/push_subscription.rb
index b57807d1c..c5dbb58ba 100644
--- a/app/models/web/push_subscription.rb
+++ b/app/models/web/push_subscription.rb
@@ -20,6 +20,10 @@ class Web::PushSubscription < ApplicationRecord
 
   has_one :session_activation, foreign_key: 'web_push_subscription_id', inverse_of: :web_push_subscription
 
+  validates :endpoint, presence: true
+  validates :key_p256dh, presence: true
+  validates :key_auth, presence: true
+
   def push(notification)
     I18n.with_locale(associated_user&.locale || I18n.default_locale) do
       push_payload(payload_for_notification(notification), 48.hours.seconds)
diff --git a/app/presenters/instance_presenter.rb b/app/presenters/instance_presenter.rb
index d8a21fa7c..2b3849bd9 100644
--- a/app/presenters/instance_presenter.rb
+++ b/app/presenters/instance_presenter.rb
@@ -20,8 +20,8 @@ class InstancePresenter
     Rails.cache.fetch('user_count') { User.confirmed.joins(:account).merge(Account.without_suspended).count }
   end
 
-  def active_user_count
-    Rails.cache.fetch('active_user_count') { Redis.current.pfcount(*(0..3).map { |i| "activity:logins:#{i.weeks.ago.utc.to_date.cweek}" }) }
+  def active_user_count(weeks = 4)
+    Rails.cache.fetch('active_user_count') { Redis.current.pfcount(*(0...weeks).map { |i| "activity:logins:#{i.weeks.ago.utc.to_date.cweek}" }) }
   end
 
   def status_count
diff --git a/app/serializers/activitypub/move_serializer.rb b/app/serializers/activitypub/move_serializer.rb
new file mode 100644
index 000000000..5675875fa
--- /dev/null
+++ b/app/serializers/activitypub/move_serializer.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class ActivityPub::MoveSerializer < ActivityPub::Serializer
+  attributes :id, :type, :target, :actor
+  attribute :virtual_object, key: :object
+
+  def id
+    [ActivityPub::TagManager.instance.uri_for(object.account), '#moves/', object.id].join
+  end
+
+  def type
+    'Move'
+  end
+
+  def target
+    ActivityPub::TagManager.instance.uri_for(object.target_account)
+  end
+
+  def virtual_object
+    ActivityPub::TagManager.instance.uri_for(object.account)
+  end
+
+  def actor
+    ActivityPub::TagManager.instance.uri_for(object.account)
+  end
+end
diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb
index f1cebbcd4..dce506fa2 100644
--- a/app/serializers/activitypub/note_serializer.rb
+++ b/app/serializers/activitypub/note_serializer.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class ActivityPub::NoteSerializer < ActivityPub::Serializer
-  context_extensions :atom_uri, :conversation, :sensitive
+  context_extensions :atom_uri, :conversation, :sensitive, :voters_count
 
   attributes :id, :type, :summary,
              :in_reply_to, :published, :url,
@@ -23,6 +23,8 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
   attribute :end_time, if: :poll_and_expires?
   attribute :closed, if: :poll_and_expired?
 
+  attribute :voters_count, if: :poll_and_voters_count?
+
   def id
     raise Mastodon::NotPermittedError, 'Local-only statuses should not be serialized' if object.local_only? && !instance_options[:allow_local_only]
     ActivityPub::TagManager.instance.uri_for(object)
@@ -142,6 +144,10 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
 
   alias end_time closed
 
+  def voters_count
+    object.preloadable_poll.voters_count
+  end
+
   def poll_and_expires?
     object.preloadable_poll&.expires_at&.present?
   end
@@ -150,6 +156,10 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
     object.preloadable_poll&.expired?
   end
 
+  def poll_and_voters_count?
+    object.preloadable_poll&.voters_count
+  end
+
   class MediaAttachmentSerializer < ActivityPub::Serializer
     context_extensions :blurhash, :focal_point
 
diff --git a/app/serializers/nodeinfo/discovery_serializer.rb b/app/serializers/nodeinfo/discovery_serializer.rb
new file mode 100644
index 000000000..07ab2a6ee
--- /dev/null
+++ b/app/serializers/nodeinfo/discovery_serializer.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class NodeInfo::DiscoverySerializer < ActiveModel::Serializer
+  include RoutingHelper
+
+  attribute :links
+
+  def links
+    [{ rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0', href: nodeinfo_schema_url }]
+  end
+end
diff --git a/app/serializers/nodeinfo/serializer.rb b/app/serializers/nodeinfo/serializer.rb
new file mode 100644
index 000000000..1a7d7a911
--- /dev/null
+++ b/app/serializers/nodeinfo/serializer.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+class NodeInfo::Serializer < ActiveModel::Serializer
+  include RoutingHelper
+
+  attributes :version, :software, :protocols, :usage
+
+  def version
+    '2.0'
+  end
+
+  def software
+    { name: 'mastodon', version: Mastodon::Version.to_s }
+  end
+
+  def services
+    { outbound: [], inbound: [] }
+  end
+
+  def protocols
+    %w(activitypub)
+  end
+
+  def usage
+    {
+      users: {
+        total: instance_presenter.user_count,
+        active_month: instance_presenter.active_user_count(4),
+        active_halfyear: instance_presenter.active_user_count(24),
+      },
+
+      local_posts: instance_presenter.status_count,
+    }
+  end
+
+  private
+
+  def instance_presenter
+    @instance_presenter ||= InstancePresenter.new
+  end
+end
diff --git a/app/serializers/rest/credential_account_serializer.rb b/app/serializers/rest/credential_account_serializer.rb
index fb195eb07..be0d763dc 100644
--- a/app/serializers/rest/credential_account_serializer.rb
+++ b/app/serializers/rest/credential_account_serializer.rb
@@ -12,6 +12,7 @@ class REST::CredentialAccountSerializer < REST::AccountSerializer
       language: user.setting_default_language,
       note: object.note,
       fields: object.fields.map(&:to_h),
+      follow_requests_count: FollowRequest.where(target_account: object).limit(40).count,
     }
   end
 end
diff --git a/app/serializers/rest/poll_serializer.rb b/app/serializers/rest/poll_serializer.rb
index 356c45b83..df6ebd0d4 100644
--- a/app/serializers/rest/poll_serializer.rb
+++ b/app/serializers/rest/poll_serializer.rb
@@ -2,12 +2,13 @@
 
 class REST::PollSerializer < ActiveModel::Serializer
   attributes :id, :expires_at, :expired,
-             :multiple, :votes_count
+             :multiple, :votes_count, :voters_count
 
   has_many :loaded_options, key: :options
   has_many :emojis, serializer: REST::CustomEmojiSerializer
 
   attribute :voted, if: :current_user?
+  attribute :own_votes, if: :current_user?
 
   def id
     object.id.to_s
@@ -21,6 +22,10 @@ class REST::PollSerializer < ActiveModel::Serializer
     object.voted?(current_user.account)
   end
 
+  def own_votes
+    object.own_votes(current_user.account)
+  end
+
   def current_user?
     !current_user.nil?
   end
diff --git a/app/serializers/rss/account_serializer.rb b/app/serializers/rss/account_serializer.rb
index 680d9de6f..e39b2b372 100644
--- a/app/serializers/rss/account_serializer.rb
+++ b/app/serializers/rss/account_serializer.rb
@@ -25,7 +25,7 @@ class RSS::AccountSerializer
             .description(status.spoiler_text.presence || Formatter.instance.format(status, inline_poll_options: true).to_str)
 
         status.media_attachments.each do |media|
-          item.enclosure(full_asset_url(media.file.url(:original, false)), media.file.content_type, length: media.file.size)
+          item.enclosure(full_asset_url(media.file.url(:original, false)), media.file.content_type, media.file.size)
         end
       end
     end
diff --git a/app/serializers/rss/tag_serializer.rb b/app/serializers/rss/tag_serializer.rb
index e8562ee87..6737fb2c9 100644
--- a/app/serializers/rss/tag_serializer.rb
+++ b/app/serializers/rss/tag_serializer.rb
@@ -23,7 +23,7 @@ class RSS::TagSerializer
             .description(status.spoiler_text.presence || Formatter.instance.format(status).to_str)
 
         status.media_attachments.each do |media|
-          item.enclosure(full_asset_url(media.file.url(:original, false)), media.file.content_type, length: media.file.size)
+          item.enclosure(full_asset_url(media.file.url(:original, false)), media.file.content_type, media.file.size)
         end
       end
     end
diff --git a/app/services/account_search_service.rb b/app/services/account_search_service.rb
index 01caaefa9..40c5f8590 100644
--- a/app/services/account_search_service.rb
+++ b/app/services/account_search_service.rb
@@ -42,11 +42,9 @@ class AccountSearchService < BaseService
     return [] if limit_for_non_exact_results.zero?
 
     @search_results ||= begin
-      if Chewy.enabled?
-        from_elasticsearch
-      else
-        from_database
-      end
+      results = from_elasticsearch if Chewy.enabled?
+      results ||= from_database
+      results
     end
   end
 
@@ -92,6 +90,8 @@ class AccountSearchService < BaseService
     ActiveRecord::Associations::Preloader.new.preload(records, :account_stat)
 
     records
+  rescue Faraday::ConnectionFailed, Parslet::ParseFailed
+    nil
   end
 
   def reputation_score_function
diff --git a/app/services/activitypub/process_poll_service.rb b/app/services/activitypub/process_poll_service.rb
index 2fbce65b9..cb4a0d460 100644
--- a/app/services/activitypub/process_poll_service.rb
+++ b/app/services/activitypub/process_poll_service.rb
@@ -28,6 +28,8 @@ class ActivityPub::ProcessPollService < BaseService
       end
     end
 
+    voters_count = @json['votersCount']
+
     latest_options = items.map { |item| item['name'].presence || item['content'] }
 
     # If for some reasons the options were changed, it invalidates all previous
@@ -39,7 +41,8 @@ class ActivityPub::ProcessPollService < BaseService
         last_fetched_at: Time.now.utc,
         expires_at: expires_at,
         options: latest_options,
-        cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 }
+        cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 },
+        voters_count: voters_count
       )
     rescue ActiveRecord::StaleObjectError
       poll.reload
diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb
index 4e75c370f..ac5503d46 100644
--- a/app/services/fetch_link_card_service.rb
+++ b/app/services/fetch_link_card_service.rb
@@ -22,7 +22,7 @@ class FetchLinkCardService < BaseService
     RedisLock.acquire(lock_options) do |lock|
       if lock.acquired?
         @card = PreviewCard.find_by(url: @url)
-        process_url if @card.nil? || @card.updated_at <= 2.weeks.ago
+        process_url if @card.nil? || @card.updated_at <= 2.weeks.ago || @card.missing_image?
       else
         raise Mastodon::RaceConditionError
       end
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index 101acdaf9..1941c2e2d 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -30,7 +30,7 @@ class FollowService < BaseService
 
     ActivityTracker.increment('activity:interactions')
 
-    if target_account.locked? || target_account.activitypub?
+    if target_account.locked? || source_account.silenced? || target_account.activitypub?
       request_follow(source_account, target_account, reblogs: reblogs)
     elsif target_account.local?
       direct_follow(source_account, target_account, reblogs: reblogs)
diff --git a/app/services/move_service.rb b/app/services/move_service.rb
new file mode 100644
index 000000000..da0c62c4e
--- /dev/null
+++ b/app/services/move_service.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+class MoveService < BaseService
+  def call(migration)
+    @migration      = migration
+    @source_account = migration.account
+    @target_account = migration.target_account
+
+    update_redirect!
+    process_local_relationships!
+    distribute_update!
+    distribute_move!
+  end
+
+  private
+
+  def update_redirect!
+    @source_account.update!(moved_to_account: @target_account)
+  end
+
+  def process_local_relationships!
+    MoveWorker.perform_async(@source_account.id, @target_account.id)
+  end
+
+  def distribute_update!
+    ActivityPub::UpdateDistributionWorker.perform_async(@source_account.id)
+  end
+
+  def distribute_move!
+    ActivityPub::MoveDistributionWorker.perform_async(@migration.id)
+  end
+end
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index 5d17f111b..936e6ac55 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -184,7 +184,7 @@ class PostStatusService < BaseService
   def poll_attributes
     return if @options[:poll].blank?
 
-    @options[:poll].merge(account: @account)
+    @options[:poll].merge(account: @account, voters_count: 0)
   end
 
   def scheduled_options
diff --git a/app/services/search_service.rb b/app/services/search_service.rb
index a5ba5dd11..3a498dcf4 100644
--- a/app/services/search_service.rb
+++ b/app/services/search_service.rb
@@ -60,7 +60,8 @@ class SearchService < BaseService
     TagSearchService.new.call(
       @query,
       limit: @limit,
-      offset: @offset
+      offset: @offset,
+      exclude_unreviewed: @options[:exclude_unreviewed]
     )
   end
 
diff --git a/app/services/tag_search_service.rb b/app/services/tag_search_service.rb
index 64dd76bb7..b78d65625 100644
--- a/app/services/tag_search_service.rb
+++ b/app/services/tag_search_service.rb
@@ -2,15 +2,15 @@
 
 class TagSearchService < BaseService
   def call(query, options = {})
-    @query  = query.strip.gsub(/\A#/, '')
-    @offset = options[:offset].to_i
-    @limit  = options[:limit].to_i
+    @query   = query.strip.gsub(/\A#/, '')
+    @offset  = options.delete(:offset).to_i
+    @limit   = options.delete(:limit).to_i
+    @options = options
 
-    if Chewy.enabled?
-      from_elasticsearch
-    else
-      from_database
-    end
+    results   = from_elasticsearch if Chewy.enabled?
+    results ||= from_database
+
+    results
   end
 
   private
@@ -63,9 +63,9 @@ class TagSearchService < BaseService
           },
 
           {
-            term: {
+            match: {
               name: {
-                value: @query,
+                query: @query,
               },
             },
           },
@@ -73,10 +73,15 @@ class TagSearchService < BaseService
       },
     }
 
-    TagsIndex.query(query).filter(filter).limit(@limit).offset(@offset).objects.compact
+    definition = TagsIndex.query(query)
+    definition = definition.filter(filter) if @options[:exclude_unreviewed]
+
+    definition.limit(@limit).offset(@offset).objects.compact
+  rescue Faraday::ConnectionFailed, Parslet::ParseFailed
+    nil
   end
 
   def from_database
-    Tag.search_for(@query, @limit, @offset)
+    Tag.search_for(@query, @limit, @offset, @options)
   end
 end
diff --git a/app/services/update_account_service.rb b/app/services/update_account_service.rb
index 01756a73d..ebf24be37 100644
--- a/app/services/update_account_service.rb
+++ b/app/services/update_account_service.rb
@@ -20,7 +20,9 @@ class UpdateAccountService < BaseService
   private
 
   def authorize_all_follow_requests(account)
-    AuthorizeFollowWorker.push_bulk(FollowRequest.where(target_account: account).select(:account_id, :target_account_id)) do |req|
+    follow_requests = FollowRequest.where(target_account: account)
+    follow_requests = follow_requests.select { |req| !req.account.silenced? }
+    AuthorizeFollowWorker.push_bulk(follow_requests) do |req|
       [req.account_id, req.target_account_id]
     end
   end
diff --git a/app/services/vote_service.rb b/app/services/vote_service.rb
index 0eeb8fd56..cb7dce6e8 100644
--- a/app/services/vote_service.rb
+++ b/app/services/vote_service.rb
@@ -12,12 +12,24 @@ class VoteService < BaseService
     @choices = choices
     @votes   = []
 
-    ApplicationRecord.transaction do
-      @choices.each do |choice|
-        @votes << @poll.votes.create!(account: @account, choice: choice)
+    already_voted = true
+
+    RedisLock.acquire(lock_options) do |lock|
+      if lock.acquired?
+        already_voted = @poll.votes.where(account: @account).exists?
+
+        ApplicationRecord.transaction do
+          @choices.each do |choice|
+            @votes << @poll.votes.create!(account: @account, choice: choice)
+          end
+        end
+      else
+        raise Mastodon::RaceConditionError
       end
     end
 
+    increment_voters_count! unless already_voted
+
     ActivityTracker.increment('activity:interactions')
 
     if @poll.account.local?
@@ -53,4 +65,18 @@ class VoteService < BaseService
   def build_json(vote)
     Oj.dump(serialize_payload(vote, ActivityPub::VoteSerializer))
   end
+
+  def increment_voters_count!
+    unless @poll.voters_count.nil?
+      @poll.voters_count = @poll.voters_count + 1
+      @poll.save
+    end
+  rescue ActiveRecord::StaleObjectError
+    @poll.reload
+    retry
+  end
+
+  def lock_options
+    { redis: Redis.current, key: "vote:#{@poll.id}:#{@account.id}" }
+  end
 end
diff --git a/app/views/about/_domain_blocks.html.haml b/app/views/about/_domain_blocks.html.haml
new file mode 100644
index 000000000..940bcb934
--- /dev/null
+++ b/app/views/about/_domain_blocks.html.haml
@@ -0,0 +1,10 @@
+%table
+  %thead
+    %tr
+      %th= t('about.unavailable_content_description.domain')
+      %th= t('about.unavailable_content_description.reason')
+  %tbody
+    - domain_blocks.each do |domain_block|
+      %tr
+        %td.nowrap= domain_block.domain
+        %td= domain_block.public_comment if display_blocks_rationale?
diff --git a/app/views/about/blocks.html.haml b/app/views/about/blocks.html.haml
deleted file mode 100644
index a81a4d1eb..000000000
--- a/app/views/about/blocks.html.haml
+++ /dev/null
@@ -1,48 +0,0 @@
-- content_for :page_title do
-  = t('domain_blocks.title', instance: site_hostname)
-
-.grid
-  .column-0
-    .box-widget.rich-formatting
-      %h2= t('domain_blocks.blocked_domains')
-      %p= t('domain_blocks.description', instance: site_hostname)
-      .table-wrapper
-        %table.blocks-table
-          %thead
-            %tr
-              %th= t('domain_blocks.domain')
-              %th.severity-column= t('domain_blocks.severity')
-              - if @show_rationale
-                %th.button-column
-          %tbody
-            - if @blocks.empty?
-              %tr
-                %td{ colspan: @show_rationale ? 3 : 2 }= t('domain_blocks.no_domain_blocks')
-            - else
-              - @blocks.each_with_index do |block, i|
-                %tr{ class: i % 2 == 0 ? 'even': nil }
-                  %td{ title: block.domain }= block.domain
-                  %td= block_severity_text(block)
-                  - if @show_rationale
-                    %td
-                      - if block.public_comment.present?
-                        %button.icon-button{ title: t('domain_blocks.show_rationale'), 'aria-label' => t('domain_blocks.show_rationale') }
-                          = fa_icon 'chevron-down fw', 'aria-hidden' => true
-                - if @show_rationale
-                  - if block.public_comment.present?
-                    %tr.rationale.hidden
-                      %td{ colspan: 3 }= block.public_comment.presence
-      %h2= t('domain_blocks.severity_legend.title')
-      - if @blocks.any? { |block| block.reject_media? }
-        %h3= t('domain_blocks.media_block')
-        %p= t('domain_blocks.severity_legend.media_block')
-      - if @blocks.any? { |block| block.severity == 'silence' }
-        %h3= t('domain_blocks.silence')
-        %p= t('domain_blocks.severity_legend.silence')
-      - if @blocks.any? { |block| block.severity == 'suspend' }
-        %h3= t('domain_blocks.suspension')
-        %p= t('domain_blocks.severity_legend.suspension')
-        - if public_fetch_mode?
-          %p= t('domain_blocks.severity_legend.suspension_disclaimer')
-  .column-1
-    = render 'application/sidebar'
diff --git a/app/views/about/more.html.haml b/app/views/about/more.html.haml
index 4922f0f54..03be3f423 100644
--- a/app/views/about/more.html.haml
+++ b/app/views/about/more.html.haml
@@ -4,7 +4,7 @@
 - content_for :header_tags do
   = render partial: 'shared/og'
 
-.grid-3
+.grid-4
   .column-0
     .public-account-header.public-account-header--no-bar
       .public-account-header__image
@@ -27,22 +27,53 @@
             = image_tag @instance_presenter.mascot&.file&.url || asset_pack_path('media/images/elephant_ui_plane.svg'), alt: ''
 
   .column-2
-    .landing-page__information.contact-widget
-      %p
-        %strong= t 'about.administered_by'
+    .contact-widget
+      %h4= t 'about.administered_by'
 
       = account_link_to(@instance_presenter.contact_account)
 
       - if @instance_presenter.site_contact_email.present?
-        %p.contact-widget__mail
-          %strong
-            = succeed ':' do
-              = t 'about.contact'
-          %br/
-          = mail_to @instance_presenter.site_contact_email, nil, title: @instance_presenter.site_contact_email
+        %h4
+          = succeed ':' do
+            = t 'about.contact'
+
+        = mail_to @instance_presenter.site_contact_email, nil, title: @instance_presenter.site_contact_email
 
   .column-3
     = render 'application/flashes'
 
-    .box-widget
-      .rich-formatting= @instance_presenter.site_extended_description.html_safe.presence || t('about.extended_description_html')
+    - if @contents.blank? && (!display_blocks? || @blocks&.empty?)
+      = nothing_here
+    - else
+      .box-widget
+        .rich-formatting
+          = @contents.html_safe
+
+          - if display_blocks? && !@blocks.empty?
+            %h2#unavailable-content= t('about.unavailable_content')
+
+            %p= t('about.unavailable_content_html')
+
+            - if (blocks = @blocks.select(&:reject_media?)) && !blocks.empty?
+              %p= t('about.unavailable_content_description.rejecting_media')
+              = render partial: 'domain_blocks', locals: { domain_blocks: blocks }
+            - if (blocks = @blocks.select(&:silence?)) && !blocks.empty?
+              %p= t('about.unavailable_content_description.silenced')
+              = render partial: 'domain_blocks', locals: { domain_blocks: blocks }
+            - if (blocks = @blocks.select(&:suspend?)) && !blocks.empty?
+              %p= t('about.unavailable_content_description.suspended')
+              = render partial: 'domain_blocks', locals: { domain_blocks: blocks }
+
+  .column-4
+    %ul.table-of-contents
+      - @table_of_contents.each do |item|
+        %li
+          = link_to item.title, "##{item.anchor}"
+
+          - unless item.children.empty?
+            %ul
+              - item.children.each do |sub_item|
+                %li= link_to sub_item.title, "##{sub_item.anchor}"
+
+      - if display_blocks? && !@blocks.empty?
+        %li= link_to t('about.unavailable_content'), '#unavailable-content'
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 06f29b79b..249e12563 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -4,35 +4,43 @@
 .dashboard__counters
   %div
     = link_to admin_accounts_url(local: 1, recent: 1) do
-      .dashboard__counters__num= number_to_human @users_count, strip_insignificant_zeros: true
+      .dashboard__counters__num{ title: number_with_delimiter(@users_count, strip_insignificant_zeros: true) }
+        = number_to_human @users_count, strip_insignificant_zeros: true
       .dashboard__counters__label= t 'admin.dashboard.total_users'
   %div
     %div
-      .dashboard__counters__num= number_to_human @registrations_week, strip_insignificant_zeros: true
+      .dashboard__counters__num{ title: number_with_delimiter(@registrations_week, strip_insignificant_zeros: true) }
+        = number_to_human @registrations_week, strip_insignificant_zeros: true
       .dashboard__counters__label= t 'admin.dashboard.week_users_new'
   %div
     %div
-      .dashboard__counters__num= number_to_human @logins_week, strip_insignificant_zeros: true
+      .dashboard__counters__num{ title: number_with_delimiter(@logins_week, strip_insignificant_zeros: true) }
+        = number_to_human @logins_week, strip_insignificant_zeros: true
       .dashboard__counters__label= t 'admin.dashboard.week_users_active'
   %div
     = link_to admin_pending_accounts_path do
-      .dashboard__counters__num= number_to_human @pending_users_count, strip_insignificant_zeros: true
+      .dashboard__counters__num{ title: number_with_delimiter(@pending_users_count, strip_insignificant_zeros: true) }
+        = number_to_human @pending_users_count, strip_insignificant_zeros: true
       .dashboard__counters__label= t 'admin.dashboard.pending_users'
   %div
     = link_to admin_reports_url do
-      .dashboard__counters__num= number_to_human @reports_count, strip_insignificant_zeros: true
+      .dashboard__counters__num{ title: number_with_delimiter(@reports_count, strip_insignificant_zeros: true) }
+        = number_to_human @reports_count, strip_insignificant_zeros: true
       .dashboard__counters__label= t 'admin.dashboard.open_reports'
   %div
     = link_to admin_tags_path(pending_review: '1') do
-      .dashboard__counters__num= number_to_human @pending_tags_count, strip_insignificant_zeros: true
+      .dashboard__counters__num{ title: number_with_delimiter(@pending_tags_count, strip_insignificant_zeros: true) }
+        = number_to_human @pending_tags_count, strip_insignificant_zeros: true
       .dashboard__counters__label= t 'admin.dashboard.pending_tags'
   %div
     %div
-      .dashboard__counters__num= number_to_human @interactions_week, strip_insignificant_zeros: true
+      .dashboard__counters__num{ title: number_with_delimiter(@interactions_week, strip_insignificant_zeros: true) }
+        = number_to_human @interactions_week, strip_insignificant_zeros: true
       .dashboard__counters__label= t 'admin.dashboard.week_interactions'
   %div
     = link_to sidekiq_url do
-      .dashboard__counters__num= number_to_human @queue_backlog, strip_insignificant_zeros: true
+      .dashboard__counters__num{ title: number_with_delimiter(@queue_backlog, strip_insignificant_zeros: true) }
+        = number_to_human @queue_backlog, strip_insignificant_zeros: true
       .dashboard__counters__label= t 'admin.dashboard.backlog'
 
 .dashboard__widgets
diff --git a/app/views/admin/tags/index.html.haml b/app/views/admin/tags/index.html.haml
index ef05a9bd6..4ab52a165 100644
--- a/app/views/admin/tags/index.html.haml
+++ b/app/views/admin/tags/index.html.haml
@@ -40,15 +40,17 @@
 
 = form_for(@form, url: batch_admin_tags_path) do |f|
   = hidden_field_tag :page, params[:page] || 1
-  = hidden_field_tag :context, params[:context]
-  = hidden_field_tag :review, params[:review]
+  = hidden_field_tag :name, params[:name] if params[:name].present?
+
+  - Admin::FilterHelper::TAGS_FILTERS.each do |key|
+    = hidden_field_tag key, params[key] if params[key].present?
 
   .batch-table
     .batch-table__toolbar
       %label.batch-table__toolbar__select.batch-checkbox-all
         = check_box_tag :batch_checkbox_all, nil, false
       .batch-table__toolbar__actions
-        - if params[:review] == 'pending_review'
+        - if params[:pending_review] == '1'
           = f.button safe_join([fa_icon('check'), t('admin.accounts.approve')]), name: :approve, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
 
           = f.button safe_join([fa_icon('times'), t('admin.accounts.reject')]), name: :reject, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
diff --git a/app/views/auth/challenges/new.html.haml b/app/views/auth/challenges/new.html.haml
new file mode 100644
index 000000000..9aef2c35d
--- /dev/null
+++ b/app/views/auth/challenges/new.html.haml
@@ -0,0 +1,15 @@
+- content_for :page_title do
+  = t('challenge.prompt')
+
+= simple_form_for @challenge, url: request.get? ? auth_challenge_path : '' do |f|
+  = f.input :return_to, as: :hidden
+
+  .field-group
+    = f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'off', :autofocus => true }, label: t('challenge.prompt'), required: true
+
+  .actions
+    = f.button :button, t('challenge.confirm'), type: :submit
+
+  %p.hint.subtle-hint= t('challenge.hint_html')
+
+.form-footer= render 'auth/shared/links'
diff --git a/app/views/auth/registrations/_status.html.haml b/app/views/auth/registrations/_status.html.haml
index b38a83d67..47112dae0 100644
--- a/app/views/auth/registrations/_status.html.haml
+++ b/app/views/auth/registrations/_status.html.haml
@@ -1,16 +1,22 @@
 %h3= t('auth.status.account_status')
 
-- if @user.account.suspended?
-  %span.negative-hint= t('user_mailer.warning.explanation.suspend')
-- elsif @user.disabled?
-  %span.negative-hint= t('user_mailer.warning.explanation.disable')
-- elsif @user.account.silenced?
-  %span.warning-hint= t('user_mailer.warning.explanation.silence')
-- elsif !@user.confirmed?
-  %span.warning-hint= t('auth.status.confirming')
-- elsif !@user.approved?
-  %span.warning-hint= t('auth.status.pending')
-- else
-  %span.positive-hint= t('auth.status.functional')
+.simple_form
+  %p.hint
+    - if @user.account.suspended?
+      %span.negative-hint= t('user_mailer.warning.explanation.suspend')
+    - elsif @user.disabled?
+      %span.negative-hint= t('user_mailer.warning.explanation.disable')
+    - elsif @user.account.silenced?
+      %span.warning-hint= t('user_mailer.warning.explanation.silence')
+    - elsif !@user.confirmed?
+      %span.warning-hint= t('auth.status.confirming')
+      = link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path
+    - elsif !@user.approved?
+      %span.warning-hint= t('auth.status.pending')
+    - elsif @user.account.moved_to_account_id.present?
+      %span.positive-hint= t('auth.status.redirecting_to', acct: @user.account.moved_to_account.acct)
+      = link_to t('migrations.cancel'), settings_migration_path
+    - else
+      %span.positive-hint= t('auth.status.functional')
 
 %hr.spacer/
diff --git a/app/views/auth/registrations/edit.html.haml b/app/views/auth/registrations/edit.html.haml
index 710ee5c68..a155c75c9 100644
--- a/app/views/auth/registrations/edit.html.haml
+++ b/app/views/auth/registrations/edit.html.haml
@@ -13,7 +13,7 @@
       .fields-row__column.fields-group.fields-row__column-6
         = f.input :email, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, required: true, disabled: current_account.suspended?
       .fields-row__column.fields-group.fields-row__column-6
-        = f.input :current_password, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.current_password'), :autocomplete => 'off' }, required: true, disabled: current_account.suspended?
+        = f.input :current_password, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.current_password'), :autocomplete => 'off' }, required: true, disabled: current_account.suspended?, hint: false
 
     .fields-row
       .fields-row__column.fields-group.fields-row__column-6
@@ -30,7 +30,18 @@
 
 = render 'sessions'
 
+%hr.spacer/
+
+%h3= t('auth.migrate_account')
+%p.muted-hint= t('auth.migrate_account_html', path: settings_migration_path)
+
+%hr.spacer/
+
+%h3= t('migrations.incoming_migrations')
+%p.muted-hint= t('migrations.incoming_migrations_html', path: settings_aliases_path)
+
 - if open_deletion? && !current_account.suspended?
   %hr.spacer/
+
   %h3= t('auth.delete_account')
   %p.muted-hint= t('auth.delete_account_html', path: settings_delete_path)
diff --git a/app/views/auth/shared/_links.html.haml b/app/views/auth/shared/_links.html.haml
index e6c3f7cca..66ed5b93f 100644
--- a/app/views/auth/shared/_links.html.haml
+++ b/app/views/auth/shared/_links.html.haml
@@ -11,7 +11,7 @@
     - if controller_name != 'passwords' && controller_name != 'registrations'
       %li= link_to t('auth.forgot_password'), new_user_password_path
 
-  - if controller_name != 'confirmations'
+  - if controller_name != 'confirmations' && (!user_signed_in? || !current_user.confirmed? || current_user.unconfirmed_email.present?)
     %li= link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path
 
   - if user_signed_in? && controller_name != 'setup'
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index a0cb7c4fe..fc690409c 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -1,11 +1,21 @@
 - content_for :content do
   .admin-wrapper
     .sidebar-wrapper
-      .sidebar
-        = link_to root_path do
-          = image_pack_tag 'logo.svg', class: 'logo', alt: 'Mastodon'
+      .sidebar-wrapper__inner
+        .sidebar
+          = link_to root_path do
+            = image_pack_tag 'logo.svg', class: 'logo', alt: 'Mastodon'
+
+          .sidebar__toggle
+            .sidebar__toggle__logo
+              = link_to root_path do
+                = svg_logo_full
+
+            = link_to '#', class: 'sidebar__toggle__icon' do
+              = fa_icon 'bars'
+
+          = render_navigation
 
-        = render_navigation
     .content-wrapper
       .content
         %h2= yield :page_title
@@ -14,4 +24,6 @@
 
         = yield
 
+    .sidebar-wrapper.sidebar-wrapper--empty
+
 = render template: 'layouts/application'
diff --git a/app/views/settings/aliases/index.html.haml b/app/views/settings/aliases/index.html.haml
new file mode 100644
index 000000000..5b6986368
--- /dev/null
+++ b/app/views/settings/aliases/index.html.haml
@@ -0,0 +1,29 @@
+- content_for :page_title do
+  = t('settings.aliases')
+
+= simple_form_for @alias, url: settings_aliases_path do |f|
+  = render 'shared/error_messages', object: @alias
+
+  %p.hint= t('aliases.hint_html')
+
+  %hr.spacer/
+
+  .fields-group
+    = f.input :acct, wrapper: :with_block_label, input_html: { autocapitalize: 'none', autocorrect: 'off' }
+
+  .actions
+    = f.button :button, t('aliases.add_new'), type: :submit, class: 'button'
+
+%hr.spacer/
+
+.table-wrapper
+  %table.table.inline-table
+    %thead
+      %tr
+        %th= t('simple_form.labels.account_alias.acct')
+        %th
+    %tbody
+      - @aliases.each do |account_alias|
+        %tr
+          %td= account_alias.acct
+          %td= table_link_to 'trash', t('aliases.remove'), settings_alias_path(account_alias), data: { method: :delete }
diff --git a/app/views/settings/exports/show.html.haml b/app/views/settings/exports/show.html.haml
index b13cea976..76ff76bd9 100644
--- a/app/views/settings/exports/show.html.haml
+++ b/app/views/settings/exports/show.html.haml
@@ -37,12 +37,16 @@
         %td= number_with_delimiter @export.total_domain_blocks
         %td= table_link_to 'download', t('exports.csv'), settings_exports_domain_blocks_path(format: :csv)
 
+%hr.spacer/
+
 %p.muted-hint= t('exports.archive_takeout.hint_html')
 
 - if policy(:backup).create?
   %p= link_to t('exports.archive_takeout.request'), settings_export_path, class: 'button', method: :post
 
 - unless @backups.empty?
+  %hr.spacer/
+
   .table-wrapper
     %table.table
       %thead
diff --git a/app/views/settings/migration/redirects/new.html.haml b/app/views/settings/migration/redirects/new.html.haml
new file mode 100644
index 000000000..017450f4b
--- /dev/null
+++ b/app/views/settings/migration/redirects/new.html.haml
@@ -0,0 +1,27 @@
+- content_for :page_title do
+  = t('settings.migrate')
+
+= simple_form_for @redirect, url: settings_migration_redirect_path do |f|
+  %p.hint= t('migrations.warning.before')
+
+  %ul.hint
+    %li.warning-hint= t('migrations.warning.redirect')
+    %li.warning-hint= t('migrations.warning.other_data')
+    %li.warning-hint= t('migrations.warning.disabled_account')
+
+  %hr.spacer/
+
+  = render 'shared/error_messages', object: @redirect
+
+  .fields-row
+    .fields-row__column.fields-group.fields-row__column-6
+      = f.input :acct, wrapper: :with_block_label, input_html: { autocapitalize: 'none', autocorrect: 'off' }, label: t('simple_form.labels.account_migration.acct'), hint: t('simple_form.hints.account_migration.acct')
+
+    .fields-row__column.fields-group.fields-row__column-6
+      - if current_user.encrypted_password.present?
+        = f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true
+      - else
+        = f.input :current_username, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true
+
+  .actions
+    = f.button :button, t('migrations.set_redirect'), type: :submit, class: 'button button--destructive'
diff --git a/app/views/settings/migrations/show.html.haml b/app/views/settings/migrations/show.html.haml
index c69061d50..078eaebc6 100644
--- a/app/views/settings/migrations/show.html.haml
+++ b/app/views/settings/migrations/show.html.haml
@@ -1,17 +1,89 @@
 - content_for :page_title do
   = t('settings.migrate')
 
-= simple_form_for @migration, as: :migration, url: settings_migration_path, html: { method: :put } do |f|
-  - if @migration.account
-    %p.hint= t('migrations.currently_redirecting')
+.simple_form
+  - if current_account.moved_to_account.present?
+    .fields-row
+      .fields-row__column.fields-group.fields-row__column-6
+        = render 'application/card', account: current_account.moved_to_account
+      .fields-row__column.fields-group.fields-row__column-6
+        %p.hint
+          %span.positive-hint= t('migrations.redirecting_to', acct: current_account.moved_to_account.acct)
 
-    .fields-group
-      = render partial: 'application/card', locals: { account: @migration.account }
+        %p.hint= t('migrations.cancel_explanation')
+
+        %p.hint= link_to t('migrations.cancel'), settings_migration_redirect_path, data: { method: :delete }
+  - else
+    %p.hint
+      %span.positive-hint= t('migrations.not_redirecting')
+
+%hr.spacer/
+
+%h3= t('auth.migrate_account')
+
+= simple_form_for @migration, url: settings_migration_path do |f|
+  - if on_cooldown?
+    %p.hint
+      %span.warning-hint= t('migrations.on_cooldown', count: ((@cooldown.cooldown_at - Time.now.utc) / 1.day.seconds).ceil)
+  - else
+    %p.hint= t('migrations.warning.before')
+
+    %ul.hint
+      %li.warning-hint= t('migrations.warning.followers')
+      %li.warning-hint= t('migrations.warning.redirect')
+      %li.warning-hint= t('migrations.warning.other_data')
+      %li.warning-hint= t('migrations.warning.backreference_required')
+      %li.warning-hint= t('migrations.warning.cooldown')
+      %li.warning-hint= t('migrations.warning.disabled_account')
+
+  %p.hint= t('migrations.warning.only_redirect_html', path: new_settings_migration_redirect_path)
+
+  %hr.spacer/
 
   = render 'shared/error_messages', object: @migration
 
-  .fields-group
-    = f.input :acct, placeholder: t('migrations.acct')
+  .fields-row
+    .fields-row__column.fields-group.fields-row__column-6
+      = f.input :acct, wrapper: :with_block_label, input_html: { autocapitalize: 'none', autocorrect: 'off' }, disabled: on_cooldown?
+
+    .fields-row__column.fields-group.fields-row__column-6
+      - if current_user.encrypted_password.present?
+        = f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true, disabled: on_cooldown?
+      - else
+        = f.input :current_username, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true, disabled: on_cooldown?
 
   .actions
-    = f.button :button, t('migrations.proceed'), type: :submit, class: 'negative'
+    = f.button :button, t('migrations.proceed_with_move'), type: :submit, class: 'button button--destructive', disabled: on_cooldown?
+
+- unless @migrations.empty?
+  %hr.spacer/
+
+  %h3= t 'migrations.past_migrations'
+
+  %hr.spacer/
+
+  .table-wrapper
+    %table.table.inline-table
+      %thead
+        %tr
+          %th= t('migrations.acct')
+          %th= t('migrations.followers_count')
+          %th
+      %tbody
+        - @migrations.each do |migration|
+          %tr
+            %td
+              - if migration.target_account.present?
+                = compact_account_link_to migration.target_account
+              - else
+                = migration.acct
+
+            %td= number_with_delimiter migration.followers_count
+
+            %td
+              %time.time-ago{ datetime: migration.created_at.iso8601, title: l(migration.created_at) }= l(migration.created_at)
+
+%hr.spacer/
+
+%h3= t 'migrations.incoming_migrations'
+%p.muted-hint= t('migrations.incoming_migrations_html', path: settings_aliases_path)
diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml
index 1f62e07d8..f5d928233 100644
--- a/app/views/settings/profiles/show.html.haml
+++ b/app/views/settings/profiles/show.html.haml
@@ -60,6 +60,11 @@
 %h6= t('auth.migrate_account')
 %p.muted-hint= t('auth.migrate_account_html', path: settings_migration_path)
 
+%hr.spacer/
+
+%h6= t 'migrations.incoming_migrations'
+%p.muted-hint= t('migrations.incoming_migrations_html', path: settings_aliases_path)
+
 - if open_deletion?
   %hr.spacer/
 
diff --git a/app/views/settings/two_factor_authentications/show.html.haml b/app/views/settings/two_factor_authentications/show.html.haml
index 93509e022..f1eecd000 100644
--- a/app/views/settings/two_factor_authentications/show.html.haml
+++ b/app/views/settings/two_factor_authentications/show.html.haml
@@ -2,33 +2,35 @@
   = t('settings.two_factor_authentication')
 
 - if current_user.otp_required_for_login
-  %p.positive-hint
-    = fa_icon 'check'
-    = ' '
-    = t 'two_factor_authentication.enabled'
+  %p.hint
+    %span.positive-hint
+      = fa_icon 'check'
+      = ' '
+      = t 'two_factor_authentication.enabled'
 
-  %hr/
+  %hr.spacer/
 
   = simple_form_for @confirmation, url: settings_two_factor_authentication_path, method: :delete do |f|
-    = f.input :otp_attempt, wrapper: :with_label, hint: t('two_factor_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { :autocomplete => 'off' }, required: true
+    .fields-group
+      = f.input :otp_attempt, wrapper: :with_block_label, hint: t('two_factor_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { :autocomplete => 'off' }, required: true
 
     .actions
-      = f.button :button, t('two_factor_authentication.disable'), type: :submit
+      = f.button :button, t('two_factor_authentication.disable'), type: :submit, class: 'negative'
 
-  %hr/
+  %hr.spacer/
 
-  %h6= t('two_factor_authentication.recovery_codes')
-  %p.muted-hint
-    = t('two_factor_authentication.lost_recovery_codes')
-    = link_to t('two_factor_authentication.generate_recovery_codes'),
-      settings_two_factor_authentication_recovery_codes_path,
-      data: { method: :post }
+  %h3= t('two_factor_authentication.recovery_codes')
+  %p.muted-hint= t('two_factor_authentication.lost_recovery_codes')
+
+  %hr.spacer/
+
+  .simple_form
+    = link_to t('two_factor_authentication.generate_recovery_codes'), settings_two_factor_authentication_recovery_codes_path, data: { method: :post }, class: 'block-button'
 
 - else
   .simple_form
     %p.hint= t('two_factor_authentication.description_html')
 
-    = link_to t('two_factor_authentication.setup'),
-      settings_two_factor_authentication_path,
-      data: { method: :post },
-      class: 'block-button'
+    %hr.spacer/
+
+    = link_to t('two_factor_authentication.setup'), settings_two_factor_authentication_path, data: { method: :post }, class: 'block-button'
diff --git a/app/views/statuses/_poll.html.haml b/app/views/statuses/_poll.html.haml
index ba34890df..d1aba6ef9 100644
--- a/app/views/statuses/_poll.html.haml
+++ b/app/views/statuses/_poll.html.haml
@@ -1,15 +1,20 @@
 - show_results = (user_signed_in? && poll.voted?(current_account)) || poll.expired?
+- own_votes = user_signed_in? ? poll.own_votes(current_account) : []
+- total_votes_count = poll.voters_count || poll.votes_count
 
 .poll
   %ul
-    - poll.loaded_options.each do |option|
+    - poll.loaded_options.each_with_index do |option, index|
       %li
         - if show_results
-          - percent = poll.votes_count > 0 ? 100 * option.votes_count / poll.votes_count : 0
+          - percent = total_votes_count > 0 ? 100 * option.votes_count / total_votes_count : 0
           %span.poll__chart{ style: "width: #{percent}%" }
 
           %label.poll__text><
-            %span.poll__number= percent.round
+            %span.poll__number><
+              - if own_votes.include?(index)
+                %i.poll__vote__mark.fa.fa-check
+              = percent.round
             = Formatter.instance.format_poll_option(status, option, autoplay: autoplay)
         - else
           %label.poll__text><
@@ -20,7 +25,10 @@
       %button.button.button-secondary{ disabled: true }
         = t('statuses.poll.vote')
 
-    %span= t('statuses.poll.total_votes', count: poll.votes_count)
+    - if poll.voters_count.nil?
+      %span= t('statuses.poll.total_votes', count: poll.votes_count)
+    - else
+      %span= t('statuses.poll.total_people', count: poll.voters_count)
 
     - unless poll.expires_at.nil?
       ·
diff --git a/app/views/user_mailer/two_factor_disabled.html.haml b/app/views/user_mailer/two_factor_disabled.html.haml
new file mode 100644
index 000000000..651c6f940
--- /dev/null
+++ b/app/views/user_mailer/two_factor_disabled.html.haml
@@ -0,0 +1,43 @@
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell.hero
+                  .email-row
+                    .col-6
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.text-center.padded
+                              %table.hero-icon.alert-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }
+                                %tbody
+                                  %tr
+                                    %td
+                                      = image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''
+
+                              %h1= t 'devise.mailer.two_factor_disabled.title'
+                              %p.lead= t 'devise.mailer.two_factor_disabled.explanation'
+
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell.content-start
+                  %table.column{ cellspacing: 0, cellpadding: 0 }
+                    %tbody
+                      %tr
+                        %td.column-cell.button-cell
+                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }
+                            %tbody
+                              %tr
+                                %td.button-primary
+                                  = link_to edit_user_registration_url do
+                                    %span= t('settings.account_settings')
diff --git a/app/views/user_mailer/two_factor_disabled.text.erb b/app/views/user_mailer/two_factor_disabled.text.erb
new file mode 100644
index 000000000..73be1ddc2
--- /dev/null
+++ b/app/views/user_mailer/two_factor_disabled.text.erb
@@ -0,0 +1,7 @@
+<%= t 'devise.mailer.two_factor_disabled.title' %>
+
+===
+
+<%= t 'devise.mailer.two_factor_disabled.explanation' %>
+
+=> <%= edit_user_registration_url %>
diff --git a/app/views/user_mailer/two_factor_enabled.html.haml b/app/views/user_mailer/two_factor_enabled.html.haml
new file mode 100644
index 000000000..fc31bd979
--- /dev/null
+++ b/app/views/user_mailer/two_factor_enabled.html.haml
@@ -0,0 +1,43 @@
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell.hero
+                  .email-row
+                    .col-6
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.text-center.padded
+                              %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }
+                                %tbody
+                                  %tr
+                                    %td
+                                      = image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''
+
+                              %h1= t 'devise.mailer.two_factor_enabled.title'
+                              %p.lead= t 'devise.mailer.two_factor_enabled.explanation'
+
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell.content-start
+                  %table.column{ cellspacing: 0, cellpadding: 0 }
+                    %tbody
+                      %tr
+                        %td.column-cell.button-cell
+                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }
+                            %tbody
+                              %tr
+                                %td.button-primary
+                                  = link_to edit_user_registration_url do
+                                    %span= t('settings.account_settings')
diff --git a/app/views/user_mailer/two_factor_enabled.text.erb b/app/views/user_mailer/two_factor_enabled.text.erb
new file mode 100644
index 000000000..4319dddbf
--- /dev/null
+++ b/app/views/user_mailer/two_factor_enabled.text.erb
@@ -0,0 +1,7 @@
+<%= t 'devise.mailer.two_factor_enabled.title' %>
+
+===
+
+<%= t 'devise.mailer.two_factor_enabled.explanation' %>
+
+=> <%= edit_user_registration_url %>
diff --git a/app/views/user_mailer/two_factor_recovery_codes_changed.html.haml b/app/views/user_mailer/two_factor_recovery_codes_changed.html.haml
new file mode 100644
index 000000000..833708868
--- /dev/null
+++ b/app/views/user_mailer/two_factor_recovery_codes_changed.html.haml
@@ -0,0 +1,43 @@
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell.hero
+                  .email-row
+                    .col-6
+                      %table.column{ cellspacing: 0, cellpadding: 0 }
+                        %tbody
+                          %tr
+                            %td.column-cell.text-center.padded
+                              %table.hero-icon.alert-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }
+                                %tbody
+                                  %tr
+                                    %td
+                                      = image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''
+
+                              %h1= t 'devise.mailer.two_factor_recovery_codes_changed.title'
+                              %p.lead= t 'devise.mailer.two_factor_recovery_codes_changed.explanation'
+
+%table.email-table{ cellspacing: 0, cellpadding: 0 }
+  %tbody
+    %tr
+      %td.email-body
+        .email-container
+          %table.content-section{ cellspacing: 0, cellpadding: 0 }
+            %tbody
+              %tr
+                %td.content-cell.content-start
+                  %table.column{ cellspacing: 0, cellpadding: 0 }
+                    %tbody
+                      %tr
+                        %td.column-cell.button-cell
+                          %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }
+                            %tbody
+                              %tr
+                                %td.button-primary
+                                  = link_to edit_user_registration_url do
+                                    %span= t('settings.account_settings')
diff --git a/app/views/user_mailer/two_factor_recovery_codes_changed.text.erb b/app/views/user_mailer/two_factor_recovery_codes_changed.text.erb
new file mode 100644
index 000000000..6ed12fc08
--- /dev/null
+++ b/app/views/user_mailer/two_factor_recovery_codes_changed.text.erb
@@ -0,0 +1,7 @@
+<%= t 'devise.mailer.two_factor_recovery_codes_changed.title' %>
+
+===
+
+<%= t 'devise.mailer.two_factor_recovery_codes_changed.explanation' %>
+
+=> <%= edit_user_registration_url %>
diff --git a/app/workers/activitypub/move_distribution_worker.rb b/app/workers/activitypub/move_distribution_worker.rb
new file mode 100644
index 000000000..bf1c0e7ae
--- /dev/null
+++ b/app/workers/activitypub/move_distribution_worker.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class ActivityPub::MoveDistributionWorker
+  include Sidekiq::Worker
+  include Payloadable
+
+  sidekiq_options queue: 'push'
+
+  def perform(migration_id)
+    @migration = AccountMigration.find(migration_id)
+    @account   = @migration.account
+
+    ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|
+      [signed_payload, @account.id, inbox_url]
+    end
+
+    ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|
+      [signed_payload, @account.id, inbox_url]
+    end
+  rescue ActiveRecord::RecordNotFound
+    true
+  end
+
+  private
+
+  def inboxes
+    @inboxes ||= @migration.account.followers.inboxes
+  end
+
+  def signed_payload
+    @signed_payload ||= Oj.dump(serialize_payload(@migration, ActivityPub::MoveSerializer, signer: @account))
+  end
+end
diff --git a/app/workers/move_worker.rb b/app/workers/move_worker.rb
new file mode 100644
index 000000000..22788716f
--- /dev/null
+++ b/app/workers/move_worker.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class MoveWorker
+  include Sidekiq::Worker
+
+  def perform(source_account_id, target_account_id)
+    @source_account = Account.find(source_account_id)
+    @target_account = Account.find(target_account_id)
+
+    if @target_account.local?
+      rewrite_follows!
+    else
+      queue_follow_unfollows!
+    end
+  rescue ActiveRecord::RecordNotFound
+    true
+  end
+
+  private
+
+  def rewrite_follows!
+    @source_account.passive_relationships
+                   .where(account: Account.local)
+                   .in_batches
+                   .update_all(target_account: @target_account)
+  end
+
+  def queue_follow_unfollows!
+    @source_account.followers.local.select(:id).find_in_batches do |accounts|
+      UnfollowFollowWorker.push_bulk(accounts.map(&:id)) { |follower_id| [follower_id, @source_account.id, @target_account.id] }
+    end
+  end
+end
diff --git a/config/application.rb b/config/application.rb
index 5fd37120d..3ced81b8f 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -13,7 +13,8 @@ require_relative '../lib/paperclip/video_transcoder'
 require_relative '../lib/paperclip/type_corrector'
 require_relative '../lib/mastodon/snowflake'
 require_relative '../lib/mastodon/version'
-require_relative '../lib/devise/ldap_authenticatable'
+require_relative '../lib/devise/two_factor_ldap_authenticatable'
+require_relative '../lib/devise/two_factor_pam_authenticatable'
 
 Dotenv::Railtie.load
 
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 311583820..fd9a5a8b9 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -71,13 +71,10 @@ end
 
 Devise.setup do |config|
   config.warden do |manager|
-    manager.default_strategies(scope: :user).unshift :database_authenticatable
-    manager.default_strategies(scope: :user).unshift :ldap_authenticatable if Devise.ldap_authentication
-    manager.default_strategies(scope: :user).unshift :pam_authenticatable  if Devise.pam_authentication
-
-    # We handle 2FA in our own sessions controller so this gets in the way
-    manager.default_strategies(scope: :user).delete :two_factor_backupable
-    manager.default_strategies(scope: :user).delete :two_factor_authenticatable
+    manager.default_strategies(scope: :user).unshift :two_factor_ldap_authenticatable if Devise.ldap_authentication
+    manager.default_strategies(scope: :user).unshift :two_factor_pam_authenticatable  if Devise.pam_authentication
+    manager.default_strategies(scope: :user).unshift :two_factor_authenticatable
+    manager.default_strategies(scope: :user).unshift :two_factor_backupable
   end
 
   # The secret key used by Devise. Devise uses this key to generate
diff --git a/config/initializers/health_check.rb b/config/initializers/health_check.rb
index eece67b10..6f1e78fed 100644
--- a/config/initializers/health_check.rb
+++ b/config/initializers/health_check.rb
@@ -3,4 +3,6 @@ HealthCheck.setup do |config|
 
   config.standard_checks = %w(database migrations cache)
   config.full_checks = %w(database migrations cache)
+  
+  config.include_error_in_response_body = false
 end
diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb
index bf0cb52a3..c65153b0a 100644
--- a/config/initializers/inflections.rb
+++ b/config/initializers/inflections.rb
@@ -18,4 +18,5 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
   inflect.acronym 'PubSubHubbub'
   inflect.acronym 'ActivityStreams'
   inflect.acronym 'JsonLd'
+  inflect.acronym 'NodeInfo'
 end
diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb
index ce4185e02..f308c2841 100644
--- a/config/initializers/paperclip.rb
+++ b/config/initializers/paperclip.rb
@@ -25,6 +25,7 @@ if ENV['S3_ENABLED'] == 'true'
     s3_protocol: s3_protocol,
     s3_host_name: s3_hostname,
     s3_headers: {
+      'X-Amz-Multipart-Threshold' => ENV.fetch('S3_MULTIPART_THRESHOLD') { 15.megabytes }.to_i,
       'Cache-Control' => 'public, max-age=315576000, immutable',
     },
     s3_permissions: ENV.fetch('S3_PERMISSION') { 'public-read' },
diff --git a/config/locales/activerecord.br.yml b/config/locales/activerecord.br.yml
index c7677c850..77fc4f2a1 100644
--- a/config/locales/activerecord.br.yml
+++ b/config/locales/activerecord.br.yml
@@ -1 +1,13 @@
+---
 br:
+  activerecord:
+    attributes:
+      poll:
+        expires_at: Deiziad termen
+        options: Dibaboù
+    errors:
+      models:
+        account:
+          attributes:
+            username:
+              invalid: nemet lizherennoù, niverennoù ha isbarrennigoù
diff --git a/config/locales/activerecord.es.yml b/config/locales/activerecord.es.yml
index f40e6c361..2fbf0ffd7 100644
--- a/config/locales/activerecord.es.yml
+++ b/config/locales/activerecord.es.yml
@@ -1,17 +1 @@
----
-es:
-  activerecord:
-    attributes:
-      poll:
-        expires_at: Vencimiento
-        options: Opciones
-    errors:
-      models:
-        account:
-          attributes:
-            username:
-              invalid: sólo letras, números y guiones bajos
-        status:
-          attributes:
-            reblog:
-              taken: del estado ya existe
+--- {}
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index 45001e6fc..a725fa349 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -10,16 +10,13 @@ ar:
     api: واجهة برمجة التطبيقات
     apps: تطبيقات الأجهزة المحمولة
     apps_platforms: إستخدم ماستودون في iOS، أندرويد وأنظمة أخرى
-    browse_directory: تصفح دليل المستخدمين وافرز بالمصالح
+    browse_directory: تصفح دليل الصفحات التعريفية وصفّي بحسب الإهتمام
     browse_public_posts: تصفح تيارًا مباشرًا مِن منشورات عامة على ماستدون
     contact: للتواصل معنا
     contact_missing: لم يتم تعيينه
     contact_unavailable: غير متوفر
     discover_users: اكتشف مستخدِمين
     documentation: الدليل
-    extended_description_html: |
-      <h3>مكان جيد للقواعد</h3>
-      <p>لم يتم بعد إدخال الوصف الطويل.</p>
     federation_hint_html: بواسطة حساب في %{instance} ستتمكن من تتبع أناس في أي خادم ماستدون وأكثر.
     generic_description: "%{domain} هو سيرفر من بين سيرفرات الشبكة"
     get_apps: جرّب تطبيقا على الموبايل
@@ -39,6 +36,9 @@ ar:
     status_count_before: نشروا
     tagline: اتبع أصدقائك وصديقاتك واكتشف آخرين وأخريات
     terms: شروط الخدمة
+    unavailable_content: محتوى غير متوفر
+    unavailable_content_description:
+      reason: 'السبب:'
     user_count_after:
       few: مستخدمين
       many: مستخدمين
@@ -85,7 +85,7 @@ ar:
       admin: المدير
       bot: روبوت
       moderator: مُشرِف
-    unavailable: الحساب غير متوفر
+    unavailable: الصفحة التعريفية غير متوفرة
     unfollow: إلغاء المتابعة
   admin:
     account_actions:
@@ -157,12 +157,12 @@ ar:
       outbox_url: رابط صندوق الصادر
       pending: في انتظار المراجعة
       perform_full_suspension: تعليق الحساب
-      profile_url: رابط الملف الشخصي
+      profile_url: رابط الصفحة التعريفية
       promote: ترقية
       protocol: البروتوكول
       public: عمومي
       push_subscription_expires: انتهاء الاشتراك ”PuSH“
-      redownload: تحديث الصفحة الشخصية
+      redownload: انعش الصفحة التعريفية
       reject: ارفض
       reject_all: ارفض الكل
       remove_avatar: حذف الصورة الرمزية
@@ -267,7 +267,7 @@ ar:
       config: الإعداد
       feature_deletions: الحسابات المحذوفة
       feature_invites: روابط الدعوات
-      feature_profile_directory: دليل الحسابات
+      feature_profile_directory: دليل الملفات التعريفية
       feature_registrations: التسجيلات
       feature_relay: المُرحّل الفديرالي
       feature_spam_check: مكافح البريد المزعج
@@ -297,7 +297,7 @@ ar:
         create: إنشاء حظر
         hint: لن تمنع كتلة المجال إنشاء إدخالات حساب في قاعدة البيانات ، ولكنها ستطبق طرق الإشراف المحددة بأثر رجعي وتلقائي على هذه الحسابات.
         severity:
-          desc_html: "<strong>Silence</strong> سيجعل مشاركات الحساب غير مرئية لأي شخص لا يتبعها. <strong>Suspend</strong> سيزيل كل محتوى الحساب ووسائطه وبيانات ملفه الشخصي. Use <strong>None</strong>  إذا كنت تريد فقط رفض ملفات الوسائط."
+          desc_html: "<strong>Silence</strong> سيجعل مشاركات الحساب غير مرئية لأي شخص لا يتبعها. <strong>Suspend</strong> سيزيل كل محتوى الحساب ووسائطه وبيانات ملفه التعريفي. Use <strong>None</strong> إذا كنت تريد فقط رفض ملفات الوسائط."
           noop: لا شيء
           silence: كتم
           suspend: تعليق
@@ -440,7 +440,7 @@ ar:
         title: إظهار الصور الحساسة في مُعاينات أوبن غراف
       profile_directory:
         desc_html: السماح للمستخدمين الكشف عن حساباتهم
-        title: تفعيل سجل الملفات الشخصية
+        title: تفعيل دليل الصفحات التعريفية
       registrations:
         closed_message:
           desc_html: يتم عرضه على الصفحة الرئيسية عندما يتم غلق تسجيل الحسابات الجديدة. يمكنكم إستخدام علامات الأيتش تي أم أل HTML
@@ -500,7 +500,14 @@ ar:
       with_media: تحتوي على وسائط
     tags:
       context: السياق
+      directory: في دليل حسابات المستخدمين
       in_directory: "%{count} في سجل حسابات المستخدمين"
+      last_active: آخر نشاط
+      most_popular: الأكثر شعبية
+      most_recent: الأحدث
+      name: الوسم
+      review: حالة المراجعة
+      reviewed: مُراجَع
       title: الوسوم
       trending_right_now: متداول اللحظة
       unique_uses_today: "%{count} منشورات اليوم"
@@ -530,7 +537,7 @@ ar:
     notification_preferences: تعديل خيارات البريد الإلكتروني
     salutation: "%{name}،"
     settings: 'تغيير تفضيلات البريد الإلكتروني: %{link}'
-    view_profile: عرض الملف الشخصي
+    view_profile: اعرض الصفحة التعريفية
     view_status: عرض المنشور
   applications:
     created: تم إنشاء التطبيق بنجاح
@@ -580,9 +587,13 @@ ar:
     following: 'مرحى! أنت الآن تتبع:'
     post_follow:
       close: أو يمكنك إغلاق هذه النافذة.
-      return: عرض الملف الشخصي للمستخدم
+      return: اظهر الملف التعريفي للمستخدم
       web: واصل إلى الويب
     title: إتباع %{acct}
+  challenge:
+    confirm: واصل
+    invalid_password: الكلمة السرية خاطئة
+    prompt: أكِّد الكلمة السرية للمواصلة
   datetime:
     distance_in_words:
       about_x_hours: "%{count}سا"
@@ -601,15 +612,12 @@ ar:
     confirm_password: قم بإدخال كلمتك السرية الحالية للتحقق من هويتك
     proceed: حذف حساب
     success_msg: تم حذف حسابك بنجاح
+    warning:
+      username_unavailable: سيبقى اسم المستخدم الخاص بك غير متوفر
   directories:
-    directory: سِجلّ الحسابات
+    directory: سِجلّ الصفحات التعريفية
     explanation: استكشف مستخدِمين آخرين حسب المواضيع التي تهمهم
     explore_mastodon: استكشف %{title}
-  domain_blocks:
-    domain: النطاق
-    severity: القوّة
-    silence: اكتم
-    suspension: علّقه
   domain_validator:
     invalid_domain: ليس بإسم نطاق صالح
   errors:
@@ -645,7 +653,7 @@ ar:
     mutes: قُمتَ بكتم
     storage: ذاكرة التخزين
   featured_tags:
-    add_new: إضافة واحد
+    add_new: أضف واحدًا جديدا
   filters:
     contexts:
       home: الخيط الزمني الرئيسي
@@ -741,9 +749,15 @@ ar:
       too_many: لا يمكن إرفاق أكثر من 4 ملفات
   migrations:
     acct: username@domain للحساب الجديد
-    currently_redirecting: 'تم تحويل رابط ملفك الشخصي إلى:'
-    proceed: حفظ
-    updated_msg: تم تحديث إعدادات ترحيل حسابك بنجاح!
+    cancel: ألغِ التوجيه
+    cancelled_msg: تم إلغاء التوجيه بنجاح.
+    errors:
+      not_found: تعذر العثور عليه
+    followers_count: المتابِعين عند الإنتقال
+    incoming_migrations: الانتقال مِن حساب آخر
+    past_migrations: التهجيرات السابقة
+    proceed_with_move: انقل مشارِكيك
+    redirecting_to: حسابك موجَّه إلى %{acct}.
   moderation:
     title: الإشراف
   notification_mailer:
@@ -893,7 +907,7 @@ ar:
     back: عودة إلى ماستدون
     delete: حذف الحسابات
     development: التطوير
-    edit_profile: تعديل الملف الشخصي
+    edit_profile: عدّل الصفحة التعريفية
     export: تصدير البيانات
     featured_tags: الوسوم الشائعة
     identity_proofs: دلائل الهوية
@@ -902,7 +916,7 @@ ar:
     migrate: تهجير الحساب
     notifications: الإخطارات
     preferences: التفضيلات
-    profile: الملف الشخصي
+    profile: الملف التعريفي
     relationships: المتابِعون والمتابَعون
     two_factor_authentication: المُصادقة بخُطوَتَيْن
   statuses:
@@ -940,6 +954,13 @@ ar:
       private: لا يمكن تدبيس تبويق لم يُنشر للعامة
       reblog: لا يمكن تثبيت ترقية
     poll:
+      total_votes:
+        few: "%{count} أصوات"
+        many: "%{count} أصوات"
+        one: صوت واحد %{count}
+        other: "%{count} صوتا"
+        two: صوتين %{count}
+        zero: بدون صوت %{count}
       vote: صوّت
     show_more: أظهر المزيد
     sign_in_to_participate: قم بتسجيل الدخول للمشاركة في هذه المحادثة
@@ -994,8 +1015,8 @@ ar:
         silence: الحساب محدود
         suspend: الحساب مُعلَّق
     welcome:
-      edit_profile_action: تهيئة الملف الشخصي
-      edit_profile_step: يُمكنك·كي تخصيص ملفك الشخصي عن طريق تحميل صورة رمزية ورأسية و بتعديل اسمك·كي العلني وأكثر. و إن أردت·تي معاينة المتابِعين و المتابعات الجُدد قبيل السماح لهم·ن بمتابَعتك فيمكنك·كي تأمين حسابك·كي.
+      edit_profile_action: تهيئة الملف التعريفي
+      edit_profile_step: يُمكنك·كي تخصيص صفحتك التعريفية عن طريق تحميل صورة رمزية ورأسية و بتعديل اسمك·كي العلني وأكثر. و إن أردت·تي معاينة المتابِعين و المتابعات الجُدد قبيل السماح لهم·ن بمتابَعتك فيمكنك·كي تأمين حسابك·كي.
       explanation: ها هي بعض النصائح قبل بداية الاستخدام
       final_action: اشرَع في النشر
       final_step: |-
diff --git a/config/locales/ast.yml b/config/locales/ast.yml
index 72b87a6ac..ed8aef235 100644
--- a/config/locales/ast.yml
+++ b/config/locales/ast.yml
@@ -8,9 +8,6 @@ ast:
     contact_missing: Nun s'afitó
     contact_unavailable: N/D
     documentation: Documentación
-    extended_description_html: |
-      <h3>Un llugar bonu pa les regles</h3>
-      <p>Entá nun se configuró la descripción estendida.</p>
     hosted_on: Mastodon ta agospiáu en %{domain}
     learn_more: Deprendi más
     source_code: Códigu fonte
@@ -199,7 +196,6 @@ ast:
       too_many: Nun puen axuntase más de 4 ficheros
   migrations:
     acct: nome_usuariu@dominiu de la cuenta nueva
-    proceed: Guardar
   notification_mailer:
     digest:
       body: Equí hai un resume de los mensaxes que nun viesti dende la última visita'l %{since}
diff --git a/config/locales/bn.yml b/config/locales/bn.yml
index 5f05fe30e..1da7aac53 100644
--- a/config/locales/bn.yml
+++ b/config/locales/bn.yml
@@ -17,9 +17,6 @@ bn:
     contact_unavailable: প্রযোজ্য নয়
     discover_users: ব্যবহারকারীদের দেখুন
     documentation: ব্যবহারবিলি
-    extended_description_html: |
-      <h3>নিয়মের জন্য উপযুক্ত জায়গা</h3>
-      <p>বিস্তারিত বিবরণ এখনো যুক্ত করা হয়নি</p>
     federation_hint_html: "%{instance}তে একটা নিবন্ধন থাকলে আপনি যেকোনো মাস্টাডন বা এধরণের অন্যান্য সার্ভারের মানুষের সাথে যুক্ত হতে পারবেন ।"
     generic_description: নেটওয়ার্কের ভেতরে %{domain} একটি সার্ভার
     get_apps: মোবাইল এপ্প একটা ব্যবহার করতে পারেন
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index bfd7c514d..eb2bfc96d 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -17,9 +17,6 @@ ca:
     contact_unavailable: N/D
     discover_users: Descobreix usuaris
     documentation: Documentació
-    extended_description_html: |
-      <h3>Un bon lloc per les regles</h3>
-      <p>Encara no s'ha configurat la descripció ampliada.</p>
     federation_hint_html: Amb un compte de %{instance} podràs seguir persones de qualsevol servidor Mastodon i altres.
     generic_description: "%{domain} és un servidor a la xarxa"
     get_apps: Prova una aplicació mòbil
@@ -627,23 +624,6 @@ ca:
     directory: Directori de perfils
     explanation: Descobreix usuaris segons els seus interessos
     explore_mastodon: Explora %{title}
-  domain_blocks:
-    blocked_domains: Llistat dels dominis limitats i bloquejats
-    description: Aquesta és la llista de servidors que %{instance} limita o en rebutja la federació.
-    domain: Domini
-    media_block: Bloqueig multimèdia
-    no_domain_blocks: "(Sense bloquejos de domini)"
-    severity: Severitat
-    severity_legend:
-      media_block: Els fitxers multimèdia procedents del servidor no es poden recuperar, emmagatzemar ni mostrar a l'usuari.
-      silence: Es poden trobar comptes de servidors silenciats, seguits i amb interacció, però els seus tuts no apareixeran en les línies de temps públiques i les seves notificacions no arribaran als usuaris locals que no els segueixen.
-      suspension: No s’emmagatzema ni es mostra contingut de servidors en suspens, ni se’ls envia cap contingut. S'ignoren les interaccions dels servidors suspesos.
-      suspension_disclaimer: Els servidors suspesos poden ocasionalment recuperar contingut públic d’aquest servidor.
-      title: Severitats
-    show_rationale: Mostra el raonament
-    silence: Silenci
-    suspension: Suspensió
-    title: "%{instance} Llistat de les instàncies bloquejades"
   domain_validator:
     invalid_domain: no es un nom de domini vàlid
   errors:
@@ -780,9 +760,6 @@ ca:
       too_many: No es poden adjuntar més de 4 fitxers
   migrations:
     acct: usuari@domini del nou compte
-    currently_redirecting: 'El teu perfil està configurat com a redirecció a:'
-    proceed: Desa
-    updated_msg: La configuració de la migració del compte s'ha actualitzat correctament!
   moderation:
     title: Moderació
   notification_mailer:
diff --git a/config/locales/co.yml b/config/locales/co.yml
index e91b1361f..40c97ec25 100644
--- a/config/locales/co.yml
+++ b/config/locales/co.yml
@@ -17,9 +17,6 @@ co:
     contact_unavailable: Micca dispunibule
     discover_users: Scopre utilizatori
     documentation: Ducumentazione
-    extended_description_html: |
-      <h3>Una bona piazza per e regule</h3>
-      <p>A descrizzione stesa ùn hè micca stata riempiuta.</p>
     federation_hint_html: Cù un contu nant'à %{instance} puderete siguità ghjente da tutti i servori Mastodon è ancu più d'altri.
     generic_description: "%{domain} hè un servore di a rete"
     get_apps: Pruvà un'applicazione di telefuninu
@@ -38,6 +35,13 @@ co:
     status_count_before: chì anu pubblicatu
     tagline: Siguità amichi è scopre ancu di più altri
     terms: Cundizione di u serviziu
+    unavailable_content: Cuntinutu micca dispunibule
+    unavailable_content_description:
+      reason: 'Ragione:'
+      rejecting_media: I fugliali media da stu servore ùn saranu micca arregistrati è e vignette ùn saranu micca affissate, duverete cliccà manualmente per accede à l'altru servore è vedeli.
+      silenced: I statuti da stu servore ùn saranu mai visti tranne nant'a vostra pagina d'accolta s'e voi siguitate l'autore.
+      suspended: Ùn puderete micca siguità qualsiasi nant'à stu servore, i dati versu o da quallà ùn saranu mai accessi, scambiati o arregistrati.
+    unavailable_content_html: Mastodon vi parmette in generale di vede u cuntinutu è interagisce cù l'utilizatori di tutti l'altri servori di u fediversu. Quessi sò l'eccezzione fatte nant'à stu servore in particulare.
     user_count_after:
       one: utilizatore
       other: utilizatori
@@ -238,8 +242,10 @@ co:
       disabled_msg: L’emoji hè stata disattivata
       emoji: Emoji
       enable: Attivà
+      enabled: Attivate
       enabled_msg: L’emoji hè stata attivata
       image_hint: PNG di 50Ko o menu
+      list: Listà
       listed: Listata
       new:
         title: Aghjunghje una nov’emoji
@@ -248,6 +254,7 @@ co:
       shortcode_hint: 2 caratteri o più, solu lettere, numeri è liniette basse
       title: Emoji parsunalizate
       uncategorized: Micca categurizatu
+      unlist: Slistà
       unlisted: Micca listata
       update_failed_msg: Ùn s’hè micca pussutu mette à ghjornu l’emoji
       updated_msg: L’emoji hè stata messa à ghjornu!
@@ -379,6 +386,7 @@ co:
       pending: In attesa di l'apprubazione di u ripetitore
       save_and_enable: Salvà è attivà
       setup: Creà una cunnessione cù un ripetitore
+      signatures_not_enabled: I ripetitori ùn marchjeranu micca currettamente mentre chì u modu sicurizatu o à lista bianca hè attivatu
       status: Statutu
       title: Ripetitori
     report_notes:
@@ -521,6 +529,10 @@ co:
       context: Cuntestu
       directory: In l'annuariu
       in_directory: "%{count} in l'annuariu"
+      last_active: Ultima attività
+      most_popular: Più pupulari
+      most_recent: Più ricente
+      name: Hashtag
       review: Statutu di verificazione
       reviewed: Verificatu
       title: Hashtag
@@ -546,6 +558,12 @@ co:
     new_trending_tag:
       body: 'U hashtag #%{name} hè in e tendenze oghji, mà ùn hè micca verificatu. Ùn sarà micca mustratu à u pubblicu eccettu s''ellu hè auturizatu, o pudete ancu salvà u furmulariu cusì per ùn mai più avè à ne sente parlà.'
       subject: Novu hashtag in attesa di rivista nant'à %{instance} (#%{name})
+  aliases:
+    add_new: Creà un pseudonimu
+    created_msg: Novu pseudonimu creatu. Pudete avà inizià u trasferimentu da u vechju contu.
+    deleted_msg: U pseudonimu hè statu sguassatu. Ùn si puderà più migrà da questu contu à quellu.
+    hint_html: Per traslucà da un altru contu à questu, quì pudete creà un pseudonimu o "alias", riquisitu per trasferì l'abbunati da u vechju contu à u novu. St'azzione sola <strong>ùn face nunda</strong> è pò esse <strong>annullata senza prublemi</strong>. <strong>A migrazione hè principiata dapoi u vechju contu</strong>.
+    remove: Sguassà u pseudonimu
   appearance:
     advanced_web_interface: Interfaccia web avanzata
     advanced_web_interface_hint: 'S''è voi vulete fà usu di a larghezza sana di u vostru screnu, l''interfaccia web avanzata vi permette di cunfigurà parechje culonne sfarente per vede tutta l''infurmazione chì vulete vede in listessu tempu: Accolta, nutificazione, linea pubblica, è tutti l''hashtag è liste chì vulete.'
@@ -605,6 +623,7 @@ co:
       confirming: In attesa di a cumplezzione di a cunfirmazione di l'e-mail.
       functional: U vostru contu hè uperaziunale.
       pending: A vostra dumanda hè in attesa di rivista da a squadra di muderazione. Quessa pò piglià un certu tempu. Avete da riceve un'e-mail s'ella hè appruvata.
+      redirecting_to: U vostru contu hè inattivu perchè riindirizza versu %{acct}.
     trouble_logging_in: Difficultà per cunnettavi?
   authorize_follow:
     already_following: Site digià abbunatu·a à stu contu
@@ -617,6 +636,11 @@ co:
       return: Vede u prufile di l’utilizatore
       web: Andà à l’interfaccia web
     title: Siguità %{acct}
+  challenge:
+    confirm: Cuntinuvà
+    hint_html: "<strong>Astuzia:</strong> Ùn avemu micca da dumandavvi stu codice per l'ore chì vene."
+    invalid_password: Chjave d'accessu micca curretta
+    prompt: Cunfirmà a chjave d'accessu per cuntinuvà
   datetime:
     distance_in_words:
       about_x_hours: "%{count}o"
@@ -632,7 +656,9 @@ co:
       x_months: "%{count}Me"
       x_seconds: "%{count}s"
   deletes:
+    challenge_not_passed: L'infurmazione entrata ùn era micca curretta
     confirm_password: Entrate a vostra chjave d’accessu attuale per verificà a vostra identità
+    confirm_username: Entrà u vostru cugnome per cunfirmà a prucedura
     proceed: Sguassà u contu
     success_msg: U vostru contu hè statu sguassatu
     warning:
@@ -650,23 +676,6 @@ co:
     directory: Annuariu di i prufili
     explanation: Scopre utilizatori à partesi di i so centri d'interessu
     explore_mastodon: Scopre à %{title}
-  domain_blocks:
-    blocked_domains: Lista di dumini bluccati è limitati
-    description: Quessa ghjè a lista di i servori limitati da o cù quelli %{instance} righjetta a federazione.
-    domain: Duminiu
-    media_block: Blucchime di media
-    no_domain_blocks: "(Nisun blucchime di duminiu)"
-    severity: Severità
-    severity_legend:
-      media_block: I fugliali media chì venenu sa stu servore ùn saranu mai ricuperati, cunservati, o affissati à l'utilizatore.
-      silence: I conti nant'à i servori silenzati ponu esse trovi, siguitati è spartuti/favurizati, mà i statuti ùn saranu micca in e linee pubbliche, è l'utilizatori lucali ch'ùn sò micca abbunati à sti conti ùn anu micca da riceve e so nutificazione.
-      suspension: U cuntinutu da i servori suspesi ùn hè mai cunservatu o affissatu, è u cuntinutu di stu servore ùn li hè micca mandatu. L'interazzione da sti servori suspesi sò ignurate.
-      suspension_disclaimer: I servori suspesi ponu ognitantu ricuperà i cuntinuti pubblichi da stu servore.
-      title: Severità
-    show_rationale: Vede ragiò
-    silence: Silenziu
-    suspension: Suspensione
-    title: Lista di servori bluccati da %{instance}
   domain_validator:
     invalid_domain: ùn hè micca un nome di duminiu currettu
   errors:
@@ -804,9 +813,34 @@ co:
       too_many: Ùn si pò micca aghjunghje più di 4 fugliali
   migrations:
     acct: cugnome@duminiu di u novu contu
-    currently_redirecting: 'U vostru prufile riindiriza tuttu versu à:'
-    proceed: Salvà
-    updated_msg: I paramettri di migrazione sò stati messi à ghjornu!
+    cancel: Annullà ridirezzione
+    cancel_explanation: L'annullazione di a ridirezzione hà da riattivà stu contu, mà ùn si puderà micca ricuperà l'abbunati chì sò digià stati trasferriti à l'altru contu.
+    cancelled_msg: Ridirezzione annullata.
+    errors:
+      already_moved: hè digià u contu induve avede traslucatu
+      missing_also_known_as: ùn fà micca riferenza à stu contu
+      move_to_self: ùn pò micca esse u contu attuale
+      not_found: ùn hè micca statu trovu
+      on_cooldown: Perioda di ricuperazione
+    followers_count: Abbunati à u mumentu di trasferimentu
+    incoming_migrations: Traslucà da un'altru contu
+    incoming_migrations_html: Per spustà da stu contu à un'altru, primu duvete <a href="%{path}">creà un pseudonimu di contu</a>.
+    moved_msg: Avà u vostru contu riindirizza versu %{acct} è i vostri abbunati sò in corsu di trasferimentu.
+    not_redirecting: U vostru contu ùn riindirizza micca ancu versu un'altru contu.
+    on_cooldown: Avede digià migratu u vostru contu. Sta funzionne sarà torna dispunibule in %{count} ghjorni.
+    past_migrations: Anziane migrazione
+    proceed_with_move: Trasferì l'abbunati
+    redirecting_to: U vostru contu riindirizza versu à %{acct}.
+    set_redirect: Creà ridirezzione
+    warning:
+      backreference_required: U novu contu deve prima esse cunfiguratu per fà rifirenza cù un pseudonimu à quessu contu
+      before: 'Nanz''à cuntinuà, leghjete ste note attentamente:'
+      cooldown: Dopu à a traslucazione, c'hè una perioda di ricuperazione in quella ùn puderete micca cambià torna di contu
+      disabled_account: U contu attuale ùn puderà più esse utilizatu dop'à st'azzione. Però, puderete accede à a spurtazione di dati o riattivà u contu.
+      followers: St'azzione hà da spiazzà tutti l'abbunati di u contu attuale nant'à u novu contu
+      only_redirect_html: Pudete ancu <a href="%{path}">mette solu una ridirezzione nant'à u vostru prufile</a>.
+      other_data: L'altri dati ùn saranu micca autumaticamente trasferiti
+      redirect: U prufile di u vostru contu attuale sarà messu à ghjornu cù una nutificazione di ridirezzione è sarà sclusu di e ricerche
   moderation:
     title: Muderazione
   notification_mailer:
@@ -951,6 +985,7 @@ co:
   settings:
     account: Contu
     account_settings: Parametri di u contu
+    aliases: Pseudonimi di contu
     appearance: Apparenza
     authorized_apps: Applicazione auturizate
     back: Ritornu nant’à Mastodon
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index 569eb35d2..eee462332 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -17,9 +17,6 @@ cs:
     contact_unavailable: Neuvedeno
     discover_users: Objevujte uživatele
     documentation: Dokumentace
-    extended_description_html: |
-      <h3>Dobré místo pro pravidla</h3>
-      <p>Rozšířený popis ještě nebyl nastaven.</p>
     federation_hint_html: S účtem na %{instance} můžete sledovat lidi na jakémkoliv serveru Mastodon a jiných službách.
     generic_description: "%{domain} je jedním ze serverů v síti"
     get_apps: Vyzkoušejte mobilní aplikaci
@@ -40,6 +37,13 @@ cs:
     status_count_before: Kteří napsali
     tagline: Sledujte své přátele a objevujte nové
     terms: Podmínky používání
+    unavailable_content: Nedostupný obsah
+    unavailable_content_description:
+      reason: 'Důvod:'
+      rejecting_media: Mediální soubory z tohoto serveru nebudou zpracovány a nebudou zobrazeny žádné náhledy. Pro prohlédnutí médií bude třeba manuálně přejít na druhý server.
+      silenced: Příspěvky z tohoto severu nebudou zobrazeni nikde kromě vašeho domovského proudu, v případě, že sledujete autora.
+      suspended: Nebudete moci sledovat nikoho z tohoto serveru, žádná data z něj nebudou zpracována či uložena a žádná data nebudou vyměněna mezi servery.
+    unavailable_content_html: Mastodon vám obvykle dovoluje prohlížet si obsah a komunikovat s uživateli z jakéhokoliv dalšího serveru ve fedivesmíru. Tohle jsou výjimky, které byly zavedeny na tomto konkrétním serveru.
     user_count_after:
       few: uživatelé
       many: uživatelů
@@ -246,8 +250,10 @@ cs:
       disabled_msg: Emoji bylo úspěšně zakázáno
       emoji: Emoji
       enable: Povolit
+      enabled: Povoleno
       enabled_msg: Emoji bylo úspěšně povoleno
       image_hint: PNG až do 50 KB
+      list: Uvést
       listed: Uvedeno
       new:
         title: Přidat nové vlastní emoji
@@ -256,6 +262,7 @@ cs:
       shortcode_hint: Alespoň 2 znaky, pouze alfanumerické znaky a podtržítka
       title: Vlastní emoji
       uncategorized: Nezařazená
+      unlist: Neuvést
       unlisted: Neuvedeno
       update_failed_msg: Nebylo možné aktualizovat toto emoji
       updated_msg: Emoji úspěšně aktualizováno!
@@ -391,6 +398,7 @@ cs:
       pending: Čekám na souhlas mostu
       save_and_enable: Uložit a povolit
       setup: Nastavit připojení k mostu
+      signatures_not_enabled: Mosty nebudou fungovat správně, dokud je povolen bezpečný režim nebo režim bílé listiny
       status: Stav
       title: Mosty
     report_notes:
@@ -533,6 +541,10 @@ cs:
       context: Kontext
       directory: V adresáři
       in_directory: "%{count} v adresáři"
+      last_active: Naposledy aktivní
+      most_popular: Nejpopulárnější
+      most_recent: Nejnovější
+      name: Hashtag
       review: Stav schválení
       reviewed: Schválen
       title: Hashtagy
@@ -558,6 +570,12 @@ cs:
     new_trending_tag:
       body: 'Hashtag #%{name} je dnes populární, nebyl však dříve schválen. Nebude zobrazen veřejně, pokud to nedovolíte. Můžete také pouze uložit formulář tak, jak je, a nikdy o něm opět neslyšet.'
       subject: Nový hashtag ke schválení na %{instance} (#%{name})
+  aliases:
+    add_new: Vytvořit alias
+    created_msg: Nový alias byl úspěšně vytvořen. Nyní můžete zahájit přesun ze starého účtu.
+    deleted_msg: Alias byl úspěšně odstraněn. Přesun z tamtoho účtu na tento již nebude možný.
+    hint_html: Chcete-li se přesunout z jiného účtu na tento, můžete si zde vytvořit alias, který je vyžadován předtím, než můžete pokračovat přesunem sledujících ze starého účtu na tento. Tato akce sama o sobě je <strong>neškodná a vratná</strong>. <strong>Přesun účtu se zahajuje ze starého účtu</strong>.
+    remove: Odpojit alias
   appearance:
     advanced_web_interface: Pokročilé webové rozhraní
     advanced_web_interface_hint: 'Chcete-li využít celé šířky vaší obrazovky, dovolí vám pokročilé webové rozhraní nastavit si mnoho různých sloupců, takže můžete vidět ve stejnou chvíli tolik informací, kolik chcete: domovskou časovou osu, oznámení, federovanou časovou osu a libovolný počet seznamů a hashtagů.'
@@ -617,6 +635,7 @@ cs:
       confirming: Čekám na dokončení potvrzení e-mailu.
       functional: Váš účet je zcela funkční.
       pending: Váš požadavek čeká na schválení naším personálem. To může nějakou dobu trvat. Pokud bude váš požadavek schválen, obdržíte e-mail.
+      redirecting_to: Váš účet je neaktivní, protože právě přesměrovává na účet %{acct}.
     trouble_logging_in: Problémy s přihlašováním?
   authorize_follow:
     already_following: Tento účet již sledujete
@@ -629,6 +648,11 @@ cs:
       return: Zobrazit profil uživatele
       web: Přejít na web
     title: Sledovat uživatele %{acct}
+  challenge:
+    confirm: Pokračovat
+    hint_html: "<strong>Tip:</strong> Po dobu hodiny vás nebudeme znovu žádat o heslo."
+    invalid_password: Neplatné heslo
+    prompt: Pokračujte potvrzením hesla
   datetime:
     distance_in_words:
       about_x_hours: "%{count} hod"
@@ -644,7 +668,9 @@ cs:
       x_months: "%{count} mesíců"
       x_seconds: "%{count} s"
   deletes:
+    challenge_not_passed: Informace, které jste zadal/a, nejsou správné
     confirm_password: Zadejte svoje současné heslo pro ověření vaší identity
+    confirm_username: Zadáním svého uživatelského jména potvrdíte proces
     proceed: Odstranit účet
     success_msg: Váš účet byl úspěšně odstraněn
     warning:
@@ -662,23 +688,6 @@ cs:
     directory: Adresář profilů
     explanation: Objevujte uživatele podle jejich zájmů
     explore_mastodon: Prozkoumejte %{title}
-  domain_blocks:
-    blocked_domains: Seznam omezených a blokovaných domén
-    description: Tohle je seznam serverů, které server %{instance} omezuje nebo odmítá federaci.
-    domain: Doména
-    media_block: Blokace médií
-    no_domain_blocks: "(Žádné blokované domény)"
-    severity: Přísnost
-    severity_legend:
-      media_block: Mediální soubory přicházející ze serveru nejsou stahovány, ukládány ani zobrazovány uživatelům.
-      silence: Účty z utišených serverů lze nalézt, sledovat a interagovat s nimi, ale jejich tooty nebudou zobrazovány na veřejných časových osách a oznámení od nich se nedostanou k místním uživatelům, kteří je nesledují.
-      suspension: Z pozastavených serverů se neukládá ani nezobrazuje žádný obsah, ani se naně žádný obsah neposílá. Interakce z pozastavených serverů jsou ignorovány.
-      suspension_disclaimer: Pozastavené servery mohou občas stahovat veřejný obsah z tohoto serveru.
-      title: Přísnosti
-    show_rationale: Zobrazit odůvodnění
-    silence: Utišení
-    suspension: Pozastavení
-    title: "%{instance} Seznam blokovaných serverů"
   domain_validator:
     invalid_domain: není platné doménové jméno
   errors:
@@ -819,10 +828,35 @@ cs:
       images_and_video: K tootu, který již obsahuje obrázky, nelze připojit video
       too_many: Nelze připojit více než 4 soubory
   migrations:
-    acct: přezdívka@doména nového účtu
-    currently_redirecting: 'Váš profil má nastaveno přesměrování na:'
-    proceed: Uložit
-    updated_msg: Vaše nastavení přesunutí účtu bylo úspěšně aktualizováno!
+    acct: Přesunuto na
+    cancel: Zrušit přesměrování
+    cancel_explanation: Zrušením přesměrování znovu aktivujete svůj aktuální účet, ale nevrátí se vám sledující, kteří byli přesměrováni na druhý účet.
+    cancelled_msg: Přesměrování bylo úspěšně zrušeno.
+    errors:
+      already_moved: je stejný účet, na který jste se již přesunul/a
+      missing_also_known_as: neodkazuje na tento účet
+      move_to_self: nemůže být aktuální účet
+      not_found: nemohl být nalezen
+      on_cooldown: Probíhá období odpočinku
+    followers_count: Sledující v době přesunu
+    incoming_migrations: Přesun z jiného účtu
+    incoming_migrations_html: Chcete-li se přesunout z jiného účtu na tento, potřebujete si nejprve <a href="%{path}">vytvořit alias účtu</a>.
+    moved_msg: Váš účet nyní přesměrovává na účet %{acct} a vaši sledující se na něj přesouvají.
+    not_redirecting: Váš účet aktuálně nepřesměrovává na žádný jiný účet.
+    on_cooldown: Nedávno jste přesunul/a svůj účet. Tato funkce bude opět dostupná za %{count} dní.
+    past_migrations: Předchozí přesuny
+    proceed_with_move: Přesunout sledující
+    redirecting_to: Váš účet přesměrovává na účet %{acct}.
+    set_redirect: Nastavit přesměrování
+    warning:
+      backreference_required: Nový účet musí být nejprve nastaven, aby odkazoval zpátky na tento
+      before: 'Před pokračováním si prosím pečlivě přečtěte tyto poznámky:'
+      cooldown: Po přesunu nastane období odpočinku, kdy se nebudete moci opět přesunout
+      disabled_account: Váš aktuální účet nebude poté zcela použitelný. Budete však mít přístup k datovým exportům a budete ho moci znovu aktivovat.
+      followers: Touto akcí přesunete všechny sledující z aktuálního účtu na nový účet
+      only_redirect_html: Alternativně můžete <a href="%{path}">nastavit pouze přesměrování na váš profil</a>.
+      other_data: Žádná další data nebudou přesunuta automaticky
+      redirect: Profil vašeho aktuálního účtu bude aktualizován s oznámením o přesměrování a bude vyloučen z hledání
   moderation:
     title: Moderování
   notification_mailer:
@@ -971,6 +1005,7 @@ cs:
   settings:
     account: Účet
     account_settings: Nastavení účtu
+    aliases: Aliasy účtů
     appearance: Vzhled
     authorized_apps: Autorizované aplikace
     back: Zpět na Mastodon
@@ -982,7 +1017,7 @@ cs:
     identity_proofs: Důkazy identity
     import: Import
     import_and_export: Import a export
-    migrate: Přesunutí účtu
+    migrate: Přesun účtu
     notifications: Oznámení
     preferences: Předvolby
     profile: Profil
diff --git a/config/locales/cy.yml b/config/locales/cy.yml
index a58ea2534..24bed1060 100644
--- a/config/locales/cy.yml
+++ b/config/locales/cy.yml
@@ -17,13 +17,13 @@ cy:
     contact_unavailable: Ddim yn berthnasol
     discover_users: Darganfod defnyddwyr
     documentation: Dogfennaeth
-    extended_description_html: |
-      <h3>Lle da ar gyfer rheolau</h3>
-      <p>Nid yw'r disgrifiad estynedig wedi ei osod eto.</p>
     federation_hint_html: Gyda cyfrif ar %{instance}, gallwch dilyn pobl ar unrhyw gweinydd Mastodon, a thu hwnt.
     generic_description: Mae %{domain} yn un gweinydd yn y rhwydwaith
     get_apps: Rhowch gynnig ar ap dyfeis symudol
     hosted_on: Mastodon wedi ei weinyddu ar %{domain}
+    instance_actor_flash: |
+      Mae'r cyfrif hwn yn actor rhithwir a ddefnyddir i gynrychioli'r gweinydd ei hun ac nid unrhyw ddefnyddiwr unigol.
+      Fe'i defnyddir at ddibenion ffederasiwn ac ni ddylid ei rwystro oni bai eich bod am rwystro'r achos cyfan, ac os felly dylech ddefnyddio bloc parth.
     learn_more: Dysu mwy
     privacy_policy: Polisi preifatrwydd
     see_whats_happening: Gweld beth sy'n digwydd
@@ -39,6 +39,13 @@ cy:
     status_count_before: Ysgriffennwyd gan
     tagline: Dilyn ffrindiau a darganfod rhai newydd
     terms: Telerau gwasanaeth
+    unavailable_content: Cynnwys nad yw ar gael
+    unavailable_content_description:
+      reason: 'Rheswm:'
+      rejecting_media: Ni fydd ffeiliau cyfryngau o'r gweinydd hwn yn cael eu prosesu ac ni fydd unrhyw fawd yn cael eu harddangos, sy'n gofyn am glicio â llaw i'r gweinydd arall.
+      silenced: Ni fydd swyddi o'r gweinydd hwn yn ymddangos yn unman heblaw eich porthiant cartref os dilynwch yr awdur.
+      suspended: Ni fyddwch yn gallu dilyn unrhyw un o'r gweinydd hwn, ac ni fydd unrhyw ddata ohono'n cael ei brosesu na'i storio, ac ni chyfnewidir unrhyw ddata.
+    unavailable_content_html: Yn gyffredinol, mae Mastodon yn caniatáu ichi weld cynnwys gan unrhyw weinyddwr arall yn y ffederasiwn a rhyngweithio â hi. Dyma'r eithriadau a wnaed ar y gweinydd penodol hwn.
     user_count_after:
       few: defnyddwyr
       many: defnyddwyr
@@ -50,6 +57,8 @@ cy:
     what_is_mastodon: Beth yw Mastodon?
   accounts:
     choices_html: 'Dewisiadau %{name}:'
+    endorsements_hint: Gallwch gymeradwyo pobl rydych chi'n eu dilyn o'r rhyngwyneb gwe, a byddan nhw'n ymddangos yma.
+    featured_tags_hint: Gallwch ychwanegu hashnodau penodol a fydd yn cael eu harddangos yma.
     follow: Dilynwch
     followers:
       few: Dilynwyr
@@ -65,6 +74,7 @@ cy:
     media: Cyfryngau
     moved_html: 'Mae %{name} wedi symud i %{new_profile_link}:'
     network_hidden: Nid yw'r wybodaeth hyn ar gael
+    never_active: Peidiwch byth
     nothing_here: Does dim byd yma!
     people_followed_by: Pobl y mae %{name} yn ei ddilyn
     people_who_follow: Pobl sy'n dilyn %{name}
@@ -199,6 +209,7 @@ cy:
       username: Enw defnyddiwr
       warn: Rhybuddio
       web: Gwe
+      whitelisted: Rhestredig wen
     action_logs:
       actions:
         assigned_to_self_report: Aseiniodd %{name} adroddiad %{target} i'w hunan
@@ -234,10 +245,12 @@ cy:
       deleted_status: "(statws wedi ei ddileu)"
       title: Log archwilio
     custom_emojis:
+      assign_category: Neilltuo categori
       by_domain: Parth
       copied_msg: Llwyddwyd i greu copi lleol o'r emoji
       copy: Copïo
       copy_failed_msg: Methwyd i greu copi lleol o'r emoji hwnnw
+      create_new_category: Create new category
       created_msg: Llwyddwyd i greu emoji!
       delete: Dileu
       destroyed_msg: Llwyddwyd i ddinistrio emojo!
@@ -254,11 +267,13 @@ cy:
       shortcode: Byrgod
       shortcode_hint: O leiaf 2 nodyn, dim ond nodau alffaniwmerig a tanlinellau
       title: Emoji unigryw
+      uncategorized: Heb gategori
       unlisted: Heb eu rhestru
       update_failed_msg: Methwyd a diweddaru'r emoji hwnnw
       updated_msg: Llwyddwyd i ddiweddaru'r emoji!
       upload: Uwchlwytho
     dashboard:
+      authorized_fetch_mode: Modd nôl awdurdodedig
       backlog: tasgau heb eu cwblhau
       config: Cyfluniad
       feature_deletions: Dileadau cyfrif
@@ -266,10 +281,13 @@ cy:
       feature_profile_directory: Cyfeiriadur proffil
       feature_registrations: Cofrestriadau
       feature_relay: Relái ffederasiwn
+      feature_spam_check: Gwrth-sbam
       feature_timeline_preview: Rhagolwg o'r ffrwd
       features: Nodweddion
       hidden_service: Ffederasiwn a gwasanaethau cudd
       open_reports: adroddiadau agored
+      pending_tags: hashnodau yn aros am adolygiad
+      pending_users: defnyddwyr yn aros am adolygiad
       recent_users: Defnyddwyr diweddar
       search: Chwilio testun llawn
       single_user_mode: Modd un defnyddiwr
@@ -281,11 +299,18 @@ cy:
       week_interactions: ymadweithiau yr wythnos hon
       week_users_active: gweithredol yr wythnos hon
       week_users_new: defnyddwyr yr wythnos hon
+      whitelist_mode: Modd rhestr wen
+    domain_allows:
+      add_new: Rhestrwch parth
+      created_msg: Rhestrwyd wen parth yn llwyddiannus
+      destroyed_msg: Mae parth wedi'i dynnu o'r rhestr wen
+      undo: Tynnwch o'r rhestr wen
     domain_blocks:
       add_new: Ychwanegu bloc parth newydd
       created_msg: Mae'r bloc parth nawr yn cael ei brosesu
       destroyed_msg: Mae'r bloc parth wedi ei ddadwneud
       domain: Parth
+      edit: Golygu bloc parth
       existing_domain_block_html: Rydych yn barod wedi gosod cyfyngau fwy llym ar %{name}, mae rhaid i chi ei <a href="%{unblock_url}">ddadblocio</a> yn gyntaf.
       new:
         create: Creu bloc
@@ -296,6 +321,8 @@ cy:
           silence: Tawelwch
           suspend: Atal
         title: Blocio parth newydd
+      private_comment: Sylw preifat
+      public_comment: Sylw cyhoeddus
       reject_media: Gwrthod dogfennau cyfryngau
       reject_media_hint: Dileu dogfennau cyfryngau wedi eu cadw yn lleol ac yn gwrthod i lawrlwytho unrhyw rai yn y dyfodol. Amherthnasol i ataliadau
       reject_reports: Gwrthod adroddiadau
@@ -319,6 +346,7 @@ cy:
         title: Dadwneud blocio parth ar gyfer %{domain}
         undo: Dadwneud
       undo: Dadwneud bloc parth
+      view: Gweld bloc parth
     email_domain_blocks:
       add_new: Ychwanegu
       created_msg: Llwyddwyd i ychwanegu parth e-bost i'r gosbrestr
@@ -346,6 +374,8 @@ cy:
         all: Pob
         limited: Gyfyngedig
         title: Goruwchwyliad
+      private_comment: Sylw preifat
+      public_comment: Sylw cyhoeddus
       title: Ffederasiwn
       total_blocked_by_us: Wedi'i bloc gan ni
       total_followed_by_them: Yn dilyn ganynt
@@ -423,6 +453,8 @@ cy:
       custom_css:
         desc_html: Addasu gwedd gyda CSS wedi lwytho ar bob tudalen
         title: CSS wedi'i addasu
+      domain_blocks:
+        all: I bawb
       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
@@ -486,6 +518,7 @@ cy:
         delete: Dileu
         nsfw_off: Marcio fel nad yw'n sensitif
         nsfw_on: Marcio'n sensitif
+      deleted: Dilëwyd
       failed_to_execute: Methwyd a gweithredu
       media:
         title: Cyfryngau
@@ -494,7 +527,13 @@ cy:
       title: Statysau cyfrif
       with_media: A chyfryngau
     tags:
+      context: Cyd-destun
+      last_active: Yn weithredol ddiwethaf
+      name: Hashnod
+      reviewed: Wedi'i adolygu
       title: Hashnodau
+      trending_right_now: Yn tueddu nawr
+      unreviewed: Heb ei adolygu
     title: Gweinyddiaeth
     warning_presets:
       add_new: Ychwanegu newydd
@@ -554,6 +593,14 @@ cy:
     reset_password: Ailosod cyfrinair
     security: Diogelwch
     set_new_password: Gosod cyfrinair newydd
+    setup:
+      title: Gosodiad
+    status:
+      account_status: Statws cyfrif
+      confirming: Aros i gadarnhad e-bost gael ei gwblhau.
+      functional: Mae eich cyfrif yn gwbl weithredol.
+      pending: Mae'ch cais yn aros i gael ei adolygu gan ein staff. Gall hyn gymryd cryn amser. Byddwch yn derbyn e-bost os caiff eich cais ei gymeradwyo.
+      redirecting_to: Mae eich cyfrif yn anactif oherwydd ei fod ar hyn o bryd yn ailgyfeirio i %{acct}.
     trouble_logging_in: Trafferdd mewngofnodi?
   authorize_follow:
     already_following: Yr ydych yn dilyn y cyfrif hwn yn barod
@@ -566,6 +613,11 @@ cy:
       return: Dangos proffil y defnyddiwr
       web: I'r wê
     title: Dilyn %{acct}
+  challenge:
+    confirm: Parhau
+    hint_html: "<strong>Awgrym:</strong> Ni fyddwn yn gofyn i chi am eich cyfrinair eto am yr awr nesaf."
+    invalid_password: Cyfrinair annilys
+    prompt: Cadarnhewch gyfrinair i barhau
   datetime:
     distance_in_words:
       about_x_hours: "%{count}awr"
@@ -581,13 +633,22 @@ cy:
       x_months: "%{count}mis"
       x_seconds: "%{count}eiliad"
   deletes:
+    challenge_not_passed: Nid oedd y wybodaeth a nodoch yn gywir
     confirm_password: Mewnbynnwch eich cyfrinair presennol i gadarnhau mai chi sydd yno
+    confirm_username: Rhowch eich enw defnyddiwr i gadarnhau'r weithdrefn
     proceed: Dileu cyfrif
     success_msg: Llwyddwyd i ddileu eich cyfrif
+    warning:
+      before: 'Cyn bwrw ymlaen, darllenwch y nodiadau hyn yn ofalus:'
+      irreversible: Ni fyddwch yn gallu adfer nac ail-greu eich cyfrif
+      username_available: Bydd eich enw defnyddiwr ar gael eto
+      username_unavailable: Ni fydd eich enw defnyddiwr ar gael
   directories:
     directory: Cyfeiriadur proffil
     explanation: Darganfod defnyddwyr yn seiliedig ar eu diddordebau
     explore_mastodon: Archwilio %{title}
+  domain_validator:
+    invalid_domain: ddim yn enw parth dilys
   errors:
     '400': The request you submitted was invalid or malformed.
     '403': Nid oes gennych ganiatad i weld y dudalen hon.
@@ -645,6 +706,7 @@ cy:
     developers: Datblygwyr
     more: Mwy…
     resources: Adnoddau
+    trending_now: Yn tueddu nawr
   generic:
     all: Popeth
     changes_saved_msg: Llwyddwyd i gadw y newidiadau!
@@ -728,9 +790,12 @@ cy:
       too_many: Ni ellir ychwanegu mwy na 4 dogfen
   migrations:
     acct: enwdefnyddiwr@parth y cyfrif newydd
-    currently_redirecting: 'Mae eich proffil wedi ei osod i ailgyfeirio i:'
-    proceed: Cadw
-    updated_msg: Diweddarwyd gosodiad mudo eich cyfrif yn llwyddiannus!
+    cancel: Canslo ailgyfeirio
+    errors:
+      not_found: ni ellid dod o hyd iddo
+    past_migrations: Ymfudiadau yn y gorffennol
+    warning:
+      before: 'Cyn bwrw ymlaen, darllenwch y nodiadau hyn yn ofalus:'
   moderation:
     title: Goruwchwyliad
   notification_mailer:
@@ -885,6 +950,7 @@ cy:
   settings:
     account: Cyfrif
     account_settings: Gosodiadau'r cyfrif
+    aliases: Aliasau cyfrif
     appearance: Arddangosiad
     authorized_apps: Apiau awdurdodedig
     back: Yn ôl i Mastodon
@@ -959,6 +1025,8 @@ cy:
     pinned: Tŵt wedi'i binio
     reblogged: hybwyd
     sensitive_content: Cynnwys sensitif
+  tags:
+    does_not_match_previous_name: ddim yn cyfateb i'r enw blaenorol
   terms:
     body_html: |
       <h2>Polisi Preifatrwydd</h2>
@@ -1076,7 +1144,9 @@ cy:
         disable: Er bod eich cyfrif wedi'i rewi, mae eich data cyfrif yn parhau i fod yn gyfan, ond ni allwch chi berfformio unrhyw gamau nes ei ddatgloi.
         silence: Pan mae eich cyfrif yn gyfyngiedig, dim ond pobl sydd yn barod yn eich dilyn yn gweld eich tŵtiau ar y gweinydd hon, a efallai byddwch yn cael eich tynnu o restrau cyhoeddus. Er hyn, gall eraill eich dilyn chi wrth law.
         suspend: Mae eich cyfrif wedi cael ei wahardd, a mae gyd o'ch tŵtiau a'ch ffeiliau cyfrwng uwchlwythadwy wedi cael eu tynnu or gweinydd yn barhaol, ac o weinyddau ble yr oedd eich dilynwyr.
+      get_in_touch: Gallwch ymateb i'r e-bost hwn i gysylltu â staff %{instance}.
       review_server_policies: Adolygu polisïau'r gweinydd
+      statuses: 'Yn benodol, ar gyfer:'
       subject:
         disable: Mae'ch cyfrif %{acct} wedi'i rewi
         none: Rhybudd am %{acct}
diff --git a/config/locales/da.yml b/config/locales/da.yml
index 06a68f684..85a5bbefd 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -14,9 +14,6 @@ da:
     contact_unavailable: Ikke tilgængeligt
     discover_users: Opdag brugere
     documentation: Dokumentation
-    extended_description_html: |
-      <h3>Et godt sted for regler</h3>
-      <p>Den udvidede beskrivelse er endnu ikke blevet opsat.</p>
     generic_description: "%{domain} er en server i netværket"
     get_apps: Prøv en mobil app
     hosted_on: Mostodon hostet på %{domain}
@@ -524,8 +521,6 @@ da:
   directories:
     directory: Profilliste
     explore_mastodon: Uforsk %{title}
-  domain_blocks:
-    domain: Domæne
   errors:
     '400': The request you submitted was invalid or malformed.
     '403': Du har ikke tilladelse til at se denne side.
@@ -633,9 +628,6 @@ da:
       too_many: Kan ikke vedhæfte mere en 4 filer
   migrations:
     acct: username@domain af den nye konto
-    currently_redirecting: 'Din profil er sat til at henvise til:'
-    proceed: Gem
-    updated_msg: Dine konti migrærings indstillinger blev opdateret!
   moderation:
     title: Moderatering
   notification_mailer:
diff --git a/config/locales/de.yml b/config/locales/de.yml
index fb988668a..6b0d132e3 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -17,9 +17,6 @@ de:
     contact_unavailable: Nicht verfügbar
     discover_users: Benutzer_innen entdecken
     documentation: Dokumentation
-    extended_description_html: |
-      <h3>Ein hervorragender Ort für Regeln</h3>
-      <p>Die erweiterte Beschreibung wurde von dem Administrator noch nicht eingestellt.</p>
     federation_hint_html: Mit einem Konto auf %{instance} wirst du in der Lage sein Nutzer_innen auf beliebigen Mastodon-Servern und darüber hinaus zu folgen.
     generic_description: "%{domain} ist ein Server im Fediversum"
     get_apps: Versuche eine mobile App
@@ -38,6 +35,13 @@ de:
     status_count_before: mit
     tagline: Finde deine Freunde und entdecke neue
     terms: Nutzungsbedingungen
+    unavailable_content: Nicht verfügbarer Inhalt
+    unavailable_content_description:
+      reason: 'Grund:'
+      rejecting_media: Mediendateien dieses Servers werden nicht verarbeitet und keine Thumbnails werden angezeigt, was manuelles anklicken auf den anderen Server erfordert.
+      silenced: Beiträge von diesem Server werden nirgends angezeigt, außer in deiner Startseite, wenn du der Person folgst, die den Beitrag verfasst hat.
+      suspended: Du kannst niemanden von diesem Server folgen, und keine Daten werden verarbeitet oder gespeichert und keine Daten ausgetauscht.
+    unavailable_content_html: Mastodon erlaubt es dir generell, mit Inhalten zu interagieren, diese anzuzeigen und mit anderen Nutzern im Fediversum über Server hinweg zu interagieren. Dies sind die Ausnahmen, die auf diesem bestimmten Server gemacht wurden.
     user_count_after:
       one: Profil
       other: Profile
@@ -238,8 +242,10 @@ de:
       disabled_msg: Das Emoji wurde deaktiviert
       emoji: Emoji
       enable: Aktivieren
+      enabled: Aktiviert
       enabled_msg: Das Emoji wurde aktiviert
       image_hint: PNG bis zu 50 kB
+      list: Liste
       listed: Gelistet
       new:
         title: Eigenes Emoji hinzufügen
@@ -248,6 +254,7 @@ de:
       shortcode_hint: Mindestens 2 Zeichen, nur Buchstaben, Ziffern und Unterstriche
       title: Eigene Emojis
       uncategorized: Nicht kategorisiert
+      unlist: Nicht listen
       unlisted: Ungelistet
       update_failed_msg: Konnte dieses Emoji nicht aktualisieren
       updated_msg: Emoji erfolgreich aktualisiert!
@@ -379,6 +386,7 @@ de:
       pending: Warte auf Zustimmung des Relays
       save_and_enable: Speichern und aktivieren
       setup: Relaisverbindung einrichten
+      signatures_not_enabled: Relais funktionieren nicht korrekt, während der sichere Modus oder der Whitelist-Modus aktiviert ist
       status: Zustand
       title: Relais
     report_notes:
@@ -521,6 +529,10 @@ de:
       context: Kontext
       directory: Im Verzeichnis
       in_directory: "%{count} im Verzeichnis"
+      last_active: Zuletzt aktiv
+      most_popular: Am beliebtesten
+      most_recent: Neuste
+      name: Hashtag
       review: Prüfstatus
       reviewed: Überprüft
       title: Hashtags
@@ -546,6 +558,12 @@ de:
     new_trending_tag:
       body: 'Der Hashtag #%{name} ist heute am trenden, aber wurde vorher noch nicht überprüft. Er wird nicht öffentlich angezeigt, es sei denn du erlaubst es oder speicherst das Formular ab und vergisst es.'
       subject: Neuer Hashtag zur Überprüfung auf %{instance} verfügbar (#%{name})
+  aliases:
+    add_new: Alias erstellen
+    created_msg: Ein neuer Alias wurde erfolgreich erstellt. Du kannst nun den Wechsel vom alten Konto starten.
+    deleted_msg: Der Alias wurde erfolgreich entfernt. Aus diesem Konto zu diesem zu verschieben ist nicht mehr möglich.
+    hint_html: Wenn du von einem Konto zu einem anderem Konto wechseln möchtest, dann kannst du einen Alias erstellen, welcher benötigt wird bevor du deine Folger_innen vom altem Account zu diesen migrierst. Die Aktion alleine ist <strong>harmlos und wi­der­ruf­lich</strong>. <strong>Die Kontenmigration wird vom altem Konto aus eingeleitet</strong>.
+    remove: Alle Aliase aufheben
   appearance:
     advanced_web_interface: Fortgeschrittene Benutzeroberfläche
     advanced_web_interface_hint: Wenn du mehr aus deiner Bildschirmbreite herausholen möchtest, erlaubt dir die fortgeschrittene Benutzeroberfläche viele unterschiedliche Spalten auf einmal zu sehen, wie z.B. deine Startseite, Benachrichtigungen, das gesamte bekannte Netz, deine Listen und beliebige Hashtags.
@@ -605,6 +623,7 @@ de:
       confirming: Warte auf die Bestätigung der E-Mail.
       functional: Dein Konto ist voll funktionsfähig.
       pending: Deine Bewerbung wird von unseren Mitarbeitern noch überprüft. Dies kann einige Zeit dauern. Du erhältst eine E-Mail, wenn deine Bewerbung genehmigt wurde.
+      redirecting_to: Dein Konto ist inaktiv, da es derzeit zu %{acct} umgeleitet wird.
     trouble_logging_in: Schwierigkeiten beim Anmelden?
   authorize_follow:
     already_following: Du folgst diesem Konto bereits
@@ -617,6 +636,11 @@ de:
       return: Zeige das Profil
       web: In der Benutzeroberfläche öffnen
     title: "%{acct} folgen"
+  challenge:
+    confirm: Fortfahren
+    hint_html: "<strong>Hinweis:</strong> Wir werden dich für die nächste Stunde nicht erneut nach deinem Passwort fragen."
+    invalid_password: Ungültiges Passwort
+    prompt: Gib dein Passwort ein um fortzufahren
   datetime:
     distance_in_words:
       about_x_hours: "%{count}h"
@@ -632,7 +656,9 @@ de:
       x_months: "%{count}mo"
       x_seconds: "%{count}s"
   deletes:
+    challenge_not_passed: Die eingegebenen Informationen waren nicht korrekt
     confirm_password: Gib dein derzeitiges Passwort ein, um deine Identität zu bestätigen
+    confirm_username: Gib deinen Benutzernamen ein, um das Verfahren zu bestätigen
     proceed: Konto löschen
     success_msg: Dein Konto wurde erfolgreich gelöscht
     warning:
@@ -650,23 +676,6 @@ de:
     directory: Profilverzeichnis
     explanation: Entdecke Benutzer_innen basierend auf deren Interessen
     explore_mastodon: Entdecke %{title}
-  domain_blocks:
-    blocked_domains: Liste der begrenzten und blockierten Domains
-    description: Dies ist die Liste der Server, die %{instance} limitiert oder dessen Föderation ablehnt.
-    domain: Domain
-    media_block: Medienblockade
-    no_domain_blocks: "(Keine Domain-Blockaden)"
-    severity: Schweregrad
-    severity_legend:
-      media_block: Mediendateien, die vom Server stammen, werden weder vom Benutzer abgerufen, gespeichert noch angezeigt.
-      silence: Konten von stummgeschalteten Servern können gefunden und gefolgt werden und man kann mit ihnen interagieren, aber ihre Beiträge werden nicht in der öffentlichen Zeitleiste erscheinen und Benachrichtigungen von ihnen werden nicht zu lokalen Benutzern gesendet, die sie nicht folgen.
-      suspension: Keine Inhalte von gesperrten Servern werden gespeichert oder angezeigt, und es werden auch keine Inhalte an sie gesendet. Die Interaktionen von gesperrten Servern werden ignoriert.
-      suspension_disclaimer: Gesperrte Server können gelegentlich öffentliche Inhalte von diesem Server abrufen.
-      title: Schweregrade
-    show_rationale: Rationale anzeigen
-    silence: Stummschalten
-    suspension: Sperre
-    title: "%{instance} Liste der blockierten Instanzen"
   domain_validator:
     invalid_domain: ist kein gültiger Domain-Name
   errors:
@@ -804,9 +813,34 @@ de:
       too_many: Es können nicht mehr als 4 Dateien angehängt werden
   migrations:
     acct: benutzername@domain des neuen Kontos
-    currently_redirecting: 'Deine Profilweiterleitung wurde gesetzt auf:'
-    proceed: Speichern
-    updated_msg: Deine Konto-Migrationseinstellungen wurden erfolgreich aktualisiert!
+    cancel: Umleitung abbrechen
+    cancel_explanation: Das Abbrechen der Umleitung wird dein aktuelles Konto erneut aktivieren, aber keine Folger_innen, die auf dieses Konto verschoben wurden, zurückholen.
+    cancelled_msg: Die Umleitung wurde erfolgreich abgebrochen.
+    errors:
+      already_moved: ist das gleiche Konto, zu dem du bereits umgezogen bist
+      missing_also_known_as: referenziert nicht zurück auf dieses Konto
+      move_to_self: darf nicht das aktuelles Konto sein
+      not_found: kann nicht gefunden werden
+      on_cooldown: Die Abklingzeit läuft gerade
+    followers_count: Folger_innen zur Zeit des Verschiebens
+    incoming_migrations: Ziehe von einem anderen Konto um
+    incoming_migrations_html: Um von einem anderen Konto zu diesem zu wechseln, musst du zuerst <a href="%{path}">einen Kontoalias</a> erstellen.
+    moved_msg: Dein Konto wird jetzt zu %{acct} weitergeleitet und deine Folger_innen werden verschoben.
+    not_redirecting: Dein Konto wird derzeit nicht auf ein anderes Konto weitergeleitet.
+    on_cooldown: Du hast dein Konto vor kurzem migriert. Diese Funktion wird in %{count} Tagen wieder verfügbar sein.
+    past_migrations: Vorherige Migrationen
+    proceed_with_move: Folger_innen verschieben
+    redirecting_to: Dein Konto wird zu %{acct} weitergeleitet.
+    set_redirect: Umleitung einrichten
+    warning:
+      backreference_required: Das neue Konto muss zuerst so konfiguriert werden, dass es auf das alte Konto referenziert
+      before: 'Bevor du fortfährst, lese bitte diese Hinweise sorgfältig durch:'
+      cooldown: Nach dem Migrieren wird es eine Abklingzeit geben, in der du das Konto nicht noch einmal migrieren kannst
+      disabled_account: Dein aktuelles Konto wird nachher nicht vollständig nutzbar sein. Du hast jedoch Zugriff auf den Datenexport sowie die Reaktivierung.
+      followers: Diese Aktion wird alle Folger_innen vom aktuellen Konto auf das neue Konto verschieben
+      only_redirect_html: Alternativ kannst du <a href="%{path}">nur eine Weiterleitung auf dein Profil</a> erstellen.
+      other_data: Keine anderen Daten werden automatisch verschoben
+      redirect: Das Profil deines aktuellen Kontos wird mit einer Weiterleitungsnachricht versehen und von Suchanfragen ausgeschlossen
   moderation:
     title: Moderation
   notification_mailer:
@@ -951,6 +985,7 @@ de:
   settings:
     account: Konto
     account_settings: Konto & Sicherheit
+    aliases: Kontoaliase
     appearance: Aussehen
     authorized_apps: Autorisierte Anwendungen
     back: Zurück zu Mastodon
diff --git a/config/locales/devise.ar.yml b/config/locales/devise.ar.yml
index 366bd81b9..90f026e10 100644
--- a/config/locales/devise.ar.yml
+++ b/config/locales/devise.ar.yml
@@ -45,6 +45,10 @@ ar:
         extra: إن لم تكن صاحب هذا الطلب ، يُرجى عدم إعارة الاهتمام لهذه الرسالة. فكلِمَتُك السرية تبقى هي مِن غير أي تعديل إلّا و فقط إن قمت بالنقر على الرابط أعلاه قصد إنشاء كلمة سرية جديدة.
         subject: 'ماستدون: تعليمات استعادة كلمة المرور'
         title: إعادة تعيين كلمة السر
+      two_factor_disabled:
+        title: إنّ 2FA معطّل
+      two_factor_enabled:
+        title: إنّ 2FA نشِط
       unlock_instructions:
         subject: 'ماستدون: تعليمات فك القفل'
     omniauth_callbacks:
diff --git a/config/locales/devise.br.yml b/config/locales/devise.br.yml
index c7677c850..3fe043754 100644
--- a/config/locales/devise.br.yml
+++ b/config/locales/devise.br.yml
@@ -1 +1,33 @@
+---
 br:
+  devise:
+    failure:
+      inactive: N'eo ket gweredekaet ho kont c'hoazh.
+      invalid: "%{authentication_keys} pe ger-tremen diwiriek."
+      last_attempt: Un esae a chom deoc'h a-raok ma vefe prennet ho kont.
+      locked: Prennet eo ho kont.
+      not_found_in_database: "%{authentication_keys} pe ger-tremen diwiriek."
+      pending: O vezañ asantet eo ho kont.
+    mailer:
+      confirmation_instructions:
+        action: Gwiriekaat ar chomlec'h postel
+        action_with_app: Kadarnaat ha distroiñ da %{app}
+        title: Gwiriekaat ar chomlec'h postel
+      email_changed:
+        subject: 'Mastodoñ : Postel kemmet'
+        title: Chomlec'h postel nevez
+      password_change:
+        explanation: Kemmet eo bet ger-tremen ho kont.
+        subject: 'Mastodoñ : Ger-tremen kemmet'
+        title: Ger-tremen kemmet
+      reconfirmation_instructions:
+        explanation: Kadarnait ar chomlec'h nevez evit cheñch ho postel.
+        subject: 'Mastodoñ : Kadarnait ar postel evit %{instance}'
+        title: Gwiriekaat ar chomlec'h postel
+      reset_password_instructions:
+        action: Cheñch ar ger-tremen
+        explanation: Goulennet ho peus ur ger-tremen nevez evit ho kont.
+    passwords:
+      updated_not_active: Kemmet eo bet ho ker-tremen ent reizh.
+    registrations:
+      signed_up: Donemat ! Kevreet oc'h.
diff --git a/config/locales/devise.co.yml b/config/locales/devise.co.yml
index 16481737f..c9511d14d 100644
--- a/config/locales/devise.co.yml
+++ b/config/locales/devise.co.yml
@@ -46,6 +46,18 @@ co:
         extra: S’ellu ùn era micca voi, ignurate stu missaghju. A chjave d’accessu ùn cambiarà micca s’è voi ùn cliccate micca u ligame.
         subject: 'Mastodon: Cambià a chjave d’accessu'
         title: Cambià a chjave
+      two_factor_disabled:
+        explanation: L'autentificazione à dui fattori per u vostru contu hè stata disattivata. A cunnessione hè avà pussibule cù l'usu solu di u vostru e-mail è di a chjave d'accessu.
+        subject: 'Mastodon: Autentificazione à dui fattori disattivata'
+        title: A2F disattivata
+      two_factor_enabled:
+        explanation: L'autentificazione à dui fattori hè stata attivata per u vostru contu. Un codice, o fiscia, generata da l'applicazione TOTP assuciata sarà dumandata per cunnettavvi.
+        subject: 'Mastodon: Autentificazione à dui fattori attivata'
+        title: A2F attivata
+      two_factor_recovery_codes_changed:
+        explanation: I codici di ricuperazione pricidenti ùn sò più validi è un novu inseme di codici hè statu creatu.
+        subject: 'Mastodon: Rigenerazione di i codici à dui fattori di ricuperazione'
+        title: Cambiamentu di i codici di ricuperazione d'A2F
       unlock_instructions:
         subject: 'Mastodon: Riapre u contu'
     omniauth_callbacks:
diff --git a/config/locales/devise.cs.yml b/config/locales/devise.cs.yml
index 94c41ed98..d1b9fc09c 100644
--- a/config/locales/devise.cs.yml
+++ b/config/locales/devise.cs.yml
@@ -46,6 +46,18 @@ cs:
         extra: Pokud jste tohle nevyžádal/a, prosím ignorujte tento e-mail. Vaše heslo nebude změněno, dokud nepřejdete na výše uvedenou adresu a nevytvoříte si nové.
         subject: 'Mastodon: Instrukce pro obnovení hesla'
         title: Obnovení hesla
+      two_factor_disabled:
+        explanation: Dvoufázové ověřování bylo pr váš účet zakázáno. Přihlašování je nyní možné pouze pomocí e-mailové adresy a hesla.
+        subject: 'Mastodon: Dvoufázové ověřování zakázáno'
+        title: 2FA zakázáno
+      two_factor_enabled:
+        explanation: Dvoufázové ověřování bylo pr váš účet povoleno. Pro přihlášení bude vyžadován token vygenerovaný spárovanou TOTP aplikací.
+        subject: 'Mastodon: Dvoufázové ověřování povoleno'
+        title: 2FA povoleno
+      two_factor_recovery_codes_changed:
+        explanation: Předchozí záložní kódy byly zrušeny a byly vygenerovány nové.
+        subject: 'Mastodon: Dvoufázové záložní kódy znovu vygenerovány'
+        title: Záložní kódy pro 2FA změněny
       unlock_instructions:
         subject: 'Mastodon: Instrukce pro odemčení účtu'
     omniauth_callbacks:
diff --git a/config/locales/devise.cy.yml b/config/locales/devise.cy.yml
index 727c71464..e5366f8cd 100644
--- a/config/locales/devise.cy.yml
+++ b/config/locales/devise.cy.yml
@@ -46,6 +46,18 @@ cy:
         extra: Os na wnaethoch gais am hyn, anwybyddwch yr e-bost hwn os gwelwch yn dda. Ni fydd eich cyfrinair yn newid nes i chi fynd at y ddolen uchod a chreu un newydd.
         subject: 'Mastodon: Ailosod cyfarwyddiadau cyfrinair'
         title: Ailosod cyfrinair
+      two_factor_disabled:
+        explanation: Mae dilysu dau ffactor ar gyfer eich cyfrif wedi'i anablu. Mae mewngofnodi bellach yn bosibl gan ddefnyddio cyfeiriad e-bost a chyfrinair yn unig.
+        subject: 'Mastodon: Dilysu dau ffactor yn anabl'
+        title: Dilysu dau ffactor yn anabl
+      two_factor_enabled:
+        explanation: Mae dilysu dau ffactor wedi'i alluogi ar gyfer eich cyfrif. Bydd angen tocyn a gynhyrchir gan yr ap TOTP pâr i fewngofnodi.
+        subject: 'Mastodon: mae dilysu dau ffactor wedi''i alluogi'
+        title: Mae dilysu dau ffactor wedi'i alluogi
+      two_factor_recovery_codes_changed:
+        explanation: Mae'r codau adfer blaenorol wedi'u hannilysu a chynhyrchwyd rhai newydd.
+        subject: 'Mastodon: Mae codau adfer dau ffactor wedi''u hadfywio'
+        title: Newidiodd codau adfer 2FA
       unlock_instructions:
         subject: 'Mastodon: Cyfarwyddiadau datgloi'
     omniauth_callbacks:
diff --git a/config/locales/devise.de.yml b/config/locales/devise.de.yml
index bd573dc3e..372090515 100644
--- a/config/locales/devise.de.yml
+++ b/config/locales/devise.de.yml
@@ -46,6 +46,18 @@ de:
         extra: Wenn du diese Anfrage nicht gestellt hast, solltest du diese E-Mail ignorieren. Dein Passwort wird sich nicht ändern solange du den obigen Link anklickst und ein neues erstellst.
         subject: 'Mastodon: Passwort zurücksetzen'
         title: Passwort zurücksetzen
+      two_factor_disabled:
+        explanation: Zwei-Faktor-Authentifizierung für dein Konto wurde deaktiviert. Login ist jetzt nur mit E-Mail-Adresse und Passwort möglich.
+        subject: 'Mastodon: Zwei‐Faktor‐Authentifizierung deaktiviert'
+        title: 2FA deaktiviert
+      two_factor_enabled:
+        explanation: Zwei-Faktor-Authentifizierung wurde für dein Konto aktiviert. Ein Token, der von der gepaarten TOTP-App generiert wird, wird für den Login benötigt.
+        subject: 'Mastodon: Zwei‐Faktor‐Authentifizierung aktiviert'
+        title: 2FA aktiviert
+      two_factor_recovery_codes_changed:
+        explanation: Die vorherigen Wiederherstellungscodes wurden ungültig gemacht und es wurden neue generiert.
+        subject: 'Mastodon: Zwei-Faktor-Wiederherstellungscodes neu generiert'
+        title: 2FA Wiederherstellungscodes geändert
       unlock_instructions:
         subject: 'Mastodon: Konto entsperren'
     omniauth_callbacks:
diff --git a/config/locales/devise.el.yml b/config/locales/devise.el.yml
index 0b5c68636..f064cbe83 100644
--- a/config/locales/devise.el.yml
+++ b/config/locales/devise.el.yml
@@ -46,6 +46,12 @@ el:
         extra: Αν δεν ζήτησες εσύ αυτή την αλλαγή, παρακαλούμε αγνόησε αυτό το email. Το συνθηματικό σου δεν θα αλλάξει μέχρι να επισκεφτείς τον παραπάνω σύνδεσμο και να δημιουργήσεις ένα καινούριο.
         subject: 'Mastodon: Οδηγίες επαναφοράς συνθηματικού'
         title: Επαναφορά συνθηματικού
+      two_factor_disabled:
+        explanation: Ο έλεγχος ταυτότητας δυο παραγόντων (2FA) έχει απενεργοποιηθεί για το λογαριασμό σου. Η σύνδεση γίνεται απλά με το email και το συνθηματικό.
+        subject: 'Mastodon: Απενεργοποιήθηκε ο έλεγχος ταυτότητας δύο παραγόντων'
+        title: Απενεργοποιημένο 2FA
+      two_factor_enabled:
+        title: Επαλήθευση δύο βημάτων ενεργή
       unlock_instructions:
         subject: 'Mastodon: Οδηγίες ξεκλειδώματος'
     omniauth_callbacks:
diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml
index 5defa6624..726d2426a 100644
--- a/config/locales/devise.en.yml
+++ b/config/locales/devise.en.yml
@@ -46,6 +46,18 @@ en:
         extra: If you didn't request this, please ignore this email. Your password won't change until you access the link above and create a new one.
         subject: 'Mastodon: Reset password instructions'
         title: Password reset
+      two_factor_disabled:
+        explanation: Two-factor authentication for your account has been disabled. Login is now possible using only e-mail address and password.
+        subject: 'Mastodon: Two-factor authentication disabled'
+        title: 2FA disabled
+      two_factor_enabled:
+        explanation: Two-factor authentication has been enabled for your account. A token generated by the paired TOTP app will be required for login.
+        subject: 'Mastodon: Two-factor authentication enabled'
+        title: 2FA enabled
+      two_factor_recovery_codes_changed:
+        explanation: The previous recovery codes have been invalidated and new ones generated.
+        subject: 'Mastodon: Two-factor recovery codes re-generated'
+        title: 2FA recovery codes changed
       unlock_instructions:
         subject: 'Mastodon: Unlock instructions'
     omniauth_callbacks:
diff --git a/config/locales/devise.es.yml b/config/locales/devise.es.yml
index 8210415f2..515d5c1ed 100644
--- a/config/locales/devise.es.yml
+++ b/config/locales/devise.es.yml
@@ -1,86 +1 @@
----
-es:
-  devise:
-    confirmations:
-      confirmed: Su direccion de email ha sido confirmada con exito.
-      send_instructions: Recibirá un correo electrónico con instrucciones sobre cómo confirmar su dirección de correo en pocos minutos.
-      send_paranoid_instructions: Si su dirección de correo electrónico existe en nuestra base de datos, recibirá un correo electrónico con instrucciones sobre cómo confirmar su dirección de correo en pocos minutos.
-    failure:
-      already_authenticated: Usted ya está registrado.
-      inactive: Su cuenta todavía no está activa.
-      invalid: Inválido %{authentication_keys} o contraseña.
-      last_attempt: Tiene un intento más antes de que su cuenta sea bloqueada.
-      locked: Su cuenta está bloqueada.
-      not_found_in_database: Inválido %{authentication_keys} o contraseña.
-      pending: Su cuenta aun se encuentra bajo revisión.
-      timeout: Su sesión ha expirado. Por favor inicie sesión de nuevo para continuar.
-      unauthenticated: Necesita iniciar sesión o registrarse antes de continuar.
-      unconfirmed: Tiene que confirmar su dirección de correo electrónico antes de continuar.
-    mailer:
-      confirmation_instructions:
-        action: Verificar dirección de correo electrónico
-        action_with_app: Confirmar y regresar a %{app}
-        explanation: Has creado una cuenta en %{host} con esta dirección de correo electrónico. Estas a un clic de activarla. Si no fue usted, por favor ignore este correo electrónico.
-        explanation_when_pending: Usted ha solicitado una invitación a %{host} con esta dirección de correo electrónico. Una vez que confirme su dirección de correo electrónico, revisaremos su aplicación. No puede iniciar sesión hasta que su aplicación sea revisada. Si su solicitud está rechazada, sus datos serán eliminados, así que no será necesaria ninguna acción adicional por ti. Si no fuera usted, por favor ignore este correo electrónico.
-        extra_html: Por favor revise <a href="%{terms_path}">las reglas de la instancia</a> y <a href="%{policy_path}">nuestros términos de servicio</a>.
-        subject: 'Mastodon: Instrucciones de confirmación para %{instance}'
-        title: Verificar dirección de correo electrónico
-      email_changed:
-        explanation: 'El correo electrónico para su cuenta esta siendo cambiada a:'
-        extra: Si usted no ha cambiado su correo electrónico, es probable que alguien haya conseguido acceso a su cuenta. Por favor cambie su contraseña inmediatamente o contacte al administrador de la instancia si usted no puede iniciar sesión.
-        subject: 'Mastodon: Correo electrónico cambiado'
-        title: Nueva dirección de correo electrónico
-      password_change:
-        explanation: La contraseña de su cuenta a sido cambiada.
-        extra: Si usted no a cambiado su contraseña. es probable que alguien a conseguido acceso a su cuenta. Por favor cambie su contraseña inmediatamente o contacte a el administrador de la instancia si usted esta bloqueado de su cuenta.
-        subject: 'Mastodon: Contraseña cambiada'
-        title: Contraseña cambiada
-      reconfirmation_instructions:
-        explanation: Confirme la nueva dirección para cambiar su coreo electrónico.
-        extra: Si no iniciaste este cambio, por favor ignora este correo. Esta dirección de correo para la cuenta de Mastodon no cambiará hasta que accedas al vinculo arriba.
-        subject: 'Mastodon: Confirme correo electrónico para %{instance}'
-        title: Verifique dirección de correo electrónico
-      reset_password_instructions:
-        action: Cambiar contraseña
-        explanation: Solicitaste una nueva contraseña para tu cuenta.
-        extra: Si no solicitaste esto, por favor ignora este correo. Tu contraseña no cambiará hasta que tu accedas al vinculo arriba y crees una nueva.
-        subject: 'Mastodon: Instrucciones para reiniciar contraseña'
-        title: Reiniciar contraseña
-      unlock_instructions:
-        subject: 'Mastodon: Instrucciones para desbloquear'
-    omniauth_callbacks:
-      failure: No podemos autentificarle desde %{kind} debido a "%{reason}".
-      success: Autentificado con éxito desde la cuenta %{kind} .
-    passwords:
-      no_token: No puede acceder a esta página sin provenir desde el correo de reinicio de contraseña. Si viene desde el correo de reinicio de contraseña, por favor asegúrese que está utilizando la dirección completa proporcionada.
-      send_instructions: Recibirá un correo electrónico con instrucciones sobre cómo reiniciar su contraseña en pocos minutos.
-      send_paranoid_instructions: Si su correo electrónico existe en nuestra base de datos, recibirá un enlace de recuperación de contraseña en su dirección de correo en pocos minutos.
-      updated: Su contraseña ha sido cambiada con éxito. Ahora ya está registrado.
-      updated_not_active: Su contraseña ha sido cambiada con éxito.
-    registrations:
-      destroyed: "¡Adios! Su cuenta ha sido cancelada con éxito. Esperamos verle pronto de nuevo."
-      signed_up: "¡Bienvenido! Se ha registrado con éxito."
-      signed_up_but_inactive: Se ha registrado con éxito. Sin embargo, no podemos identificarle porque su cuenta no ha sido activada todavía.
-      signed_up_but_locked: Se ha registrado con éxito. Sin embargo, no podemos identificarle porque su cuenta está bloqueada.
-      signed_up_but_pending: Un mensaje con un enlace de confirmacion ha sido enviado a su direccion de email. Luego de clickear el link revisaremos su aplicacion. Seras notificado si es aprovada.
-      signed_up_but_unconfirmed: Un mensaje con un enlace de confirmación ha sido enviado a su correo electrónico. Por favor siga el enlace para activar su cuenta.
-      update_needs_confirmation: Ha actualizado su cuenta con éxito, pero necesitamos verificar su nueva dirección de correo. Por favor compruebe su correo y siga el enlace para confirmar su nueva dirección de correo.
-      updated: su cuenta ha sido actualizada con éxito.
-    sessions:
-      already_signed_out: Cerró sesión con éxito.
-      signed_in: Se registró con éxito.
-      signed_out: Cerró sesión con éxito.
-    unlocks:
-      send_instructions: Recibirá un correo electrónico con instrucciones sobre cómo desbloquear su cuenta en pocos minutos.
-      send_paranoid_instructions: Si su cuenta existe, recibirá un correo electrónico con instrucciones sobre cómo desbloquearla en pocos minutos.
-      unlocked: Su cuenta ha sido desbloqueada con éxito. Por favor inicie sesión para continuar.
-  errors:
-    messages:
-      already_confirmed: ya fue confirmado, por favor intente iniciar sesión
-      confirmation_period_expired: necesita ser confirmado dentro de %{period}, por favor pida una nueva
-      expired: ha expirado, por favor pida una nueva
-      not_found: no encontrado
-      not_locked: no fue bloqueada
-      not_saved:
-        one: '1 error prohibió este %{resource} de ser guardado:'
-        other: "%{count} errores prohibieron este %{resource} de ser guardado:"
+es-AR:
diff --git a/config/locales/devise.fa.yml b/config/locales/devise.fa.yml
index 963572e6b..0954c8484 100644
--- a/config/locales/devise.fa.yml
+++ b/config/locales/devise.fa.yml
@@ -46,6 +46,18 @@ fa:
         extra: اگر شما چنین درخواستی نکردید، لطفاً این ایمیل را نادیده بگیرید. تا زمانی که شما پیوند بالا را باز نکنید و رمز تازه‌ای نسازید، رمز شما عوض نخواهد شد.
         subject: 'ماستدون: راهنمایی برای بازنشانی رمز'
         title: بازنشانی رمز
+      two_factor_disabled:
+        explanation: ورود دومرحله‌ای برای حساب شما غیرفعال شده است. از الان می‌توانید تنها با نشانی ایمیل و رمز وارد حساب خود شوید.
+        subject: 'ماستدون: ورود دومرحله‌ای فعال نیست'
+        title: ورود دومرحله‌ای غیرفعال
+      two_factor_enabled:
+        explanation: ورود دومرحله‌ای برای حساب شما فعال شده است. برای ورود به کدی نیاز خواهید داشت که نرم‌افزار TOTP از پیش تنظیم شده برایتان می‌سازد.
+        subject: 'ماستدون: ورود دومرحله‌ای فعال است'
+        title: ورود دومرحله‌ای فعال
+      two_factor_recovery_codes_changed:
+        explanation: کدهای بازیابی قبلی نامعتبر شده‌اند و کدهای تازه‌ای ساخته شده‌اند.
+        subject: 'ماستدون: کدهای بازیابی برای ورود دومرحله‌ای دوباره ساخته شدند'
+        title: کدهای ورود دومرحله‌ای تغییر کرد
       unlock_instructions:
         subject: 'ماستدون: راهنمایی برای بازکردن قفل'
     omniauth_callbacks:
diff --git a/config/locales/devise.fr.yml b/config/locales/devise.fr.yml
index 321e72f4a..dc89b478b 100644
--- a/config/locales/devise.fr.yml
+++ b/config/locales/devise.fr.yml
@@ -46,6 +46,18 @@ fr:
         extra: Si vous ne l’avez pas demandé, veuillez ignorer ce courriel. Votre mot de passe ne changera pas tant que vous n’aurez pas cliqué sur le lien ci-dessus et que vous n’en aurez pas créé un nouveau.
         subject: 'Mastodon : Instructions pour changer votre mot de passe'
         title: Réinitialisation du mot de passe
+      two_factor_disabled:
+        explanation: L'authentification à deux facteurs pour votre compte a été désactivée. La connexion est maintenant possible en utilisant uniquement l'adresse courriel et le mot de passe.
+        subject: 'Mastodon : authentification à deux facteurs désactivée'
+        title: 2FA désactivée
+      two_factor_enabled:
+        explanation: L'authentification à deux facteurs a été activée pour votre compte. Un jeton généré par l'application appariée TOTP sera nécessaire pour vous connecter.
+        subject: 'Mastodon : authentification à deux facteurs activée'
+        title: A2F activée
+      two_factor_recovery_codes_changed:
+        explanation: Les codes de récupération précédents ont été invalidés et de nouveaux sont générés.
+        subject: 'Mastodon : codes de récupération à deux facteurs ré-générés'
+        title: Codes de récupération 2FA modifiés
       unlock_instructions:
         subject: 'Mastodon : Instructions pour déverrouiller votre compte'
     omniauth_callbacks:
diff --git a/config/locales/devise.gl.yml b/config/locales/devise.gl.yml
index 60a935a8a..0ce335576 100644
--- a/config/locales/devise.gl.yml
+++ b/config/locales/devise.gl.yml
@@ -46,6 +46,18 @@ gl:
         extra: Si non fixo esta solicitude, por favor ignore este correo. O seu contrasinal non cambiará ate que acceda a ligazón superior e cree unha nova.
         subject: 'Mastodon: Instruccións para restablecer o contrasinal'
         title: Restablecer contrasinal
+      two_factor_disabled:
+        explanation: Desactivouse o segundo factor de autenticación para túa conta. Agora xa podes conectarte utilizando só o correo-e e contrasinal.
+        subject: 'Mastodon: Autenticación con dobre factor desactivada'
+        title: 2FA desactivada
+      two_factor_enabled:
+        explanation: A autenticación con dobre factor foi activada para a túa conta. Pedirase o testemuño xerado pola aplicación TOTP emparellada.
+        subject: 'Mastodon: Activouse o dobre factor de autenticación'
+        title: 2FA activado
+      two_factor_recovery_codes_changed:
+        explanation: Os códigos de recuperación anteriores quedan anulados e os novos foron creados.
+        subject: 'Mastodon: Código de recuperación do dobre factor rexenerados'
+        title: Códigos de recuperación 2FA cambiados
       unlock_instructions:
         subject: 'Mastodon: Instruccións para desbloquear'
     omniauth_callbacks:
diff --git a/config/locales/devise.hu.yml b/config/locales/devise.hu.yml
index e495cb5f0..62888be74 100644
--- a/config/locales/devise.hu.yml
+++ b/config/locales/devise.hu.yml
@@ -46,6 +46,18 @@ hu:
         extra: Amennyiben nem te kezdeményezted a módosítást, kérjük tekintsd ezt az e-mailt tárgytalannak. A Mastodon fiókodhoz tartozó jelszavad változatlan marad mindaddig, amíg újat nem hozol létre a fenti linkre kattintva.
         subject: 'Mastodon: Jelszó visszaállítási lépések'
         title: Jelszó visszaállítása
+      two_factor_disabled:
+        explanation: A fiókod kétlépcsős hitelesítését letiltottuk. A bejelentkezés most már csak e-mail címmel és jelszóval lehetséges.
+        subject: Kétlépcsős azonosítás letiltva
+        title: Kétlépcsős hitelesítés engedélyezve
+      two_factor_enabled:
+        explanation: Kétlépcsős hitelesítés engedélyezve van a fiókodban. Bejelentkezéshez a párosított TOTP alkalmazás által létrehozott tokenre lesz szükség.
+        subject: Kétlépcsős azonosítás engedélyezve
+        title: Kétlépcsős hitelesítés engedélyezve
+      two_factor_recovery_codes_changed:
+        explanation: A korábbi helyreállítási kódokat letiltottuk, és újakat generáltunk.
+        subject: Kétlépcsős helyreállítási kódok újra létrejöttek
+        title: A kétlépcsős kódok megváltozott
       unlock_instructions:
         subject: 'Mastodon: Feloldási lépések'
     omniauth_callbacks:
diff --git a/config/locales/devise.it.yml b/config/locales/devise.it.yml
index b603e12c6..dca5e3caa 100644
--- a/config/locales/devise.it.yml
+++ b/config/locales/devise.it.yml
@@ -46,6 +46,17 @@ it:
         extra: Se questo cambiamento non è stato chiesto da te, ignora questa email. La tua password non verrà cambiata finché non accedi tramite il link qui sopra e ne crei una nuova.
         subject: 'Mastodon: Istruzioni per il reset della password'
         title: Ripristino password
+      two_factor_disabled:
+        explanation: L'autenticazione a due fattori per il tuo account è stata disattivata. Il login è ora possibile utilizzando solo l'indirizzo e-mail e la password.
+        subject: 'Mastodon: Autenticazione a due fattori disattivata'
+        title: 2FA disabilitata
+      two_factor_enabled:
+        explanation: L'autenticazione a due fattori è stata attivata per il tuo account. Un token generato dall'app TOTP collegata sarà richiesto per il login.
+        subject: 'Mastodon: Autenticazione a due fattori attivata'
+        title: 2FA abilitata
+      two_factor_recovery_codes_changed:
+        subject: 'Mastodon: codici di recupero a due fattori ri-generati'
+        title: Codici di recupero 2FA modificati
       unlock_instructions:
         subject: 'Mastodon: Istruzioni di sblocco'
     omniauth_callbacks:
diff --git a/config/locales/devise.ja.yml b/config/locales/devise.ja.yml
index dc147be62..ffdbd1b60 100644
--- a/config/locales/devise.ja.yml
+++ b/config/locales/devise.ja.yml
@@ -46,6 +46,18 @@ ja:
         extra: この要求に心当たりがない場合、このメールを無視してください。上記リンク先にアクセスし新しいものを作成するまでパスワードは変更されません。
         subject: 'Mastodon: パスワード再発行'
         title: パスワード再発行
+      two_factor_disabled:
+        explanation: あなたのアカウントの二段階認証が無効化されました。メールとパスワードのみでログインできます。
+        subject: 'Mastodon: 二段階認証が無効になりました'
+        title: 二段階認証が無効化されました
+      two_factor_enabled:
+        explanation: あなたのアカウントの二段階認証が有効化されました。ログインするには TOTP アプリで生成されたコードが必要です。
+        subject: 'Mastodon: 二段階認証が有効になりました'
+        title: 二段階認証が有効化されました
+      two_factor_recovery_codes_changed:
+        explanation: 以前のリカバリーコードが無効化され、新しいコードが生成されました。
+        subject: 'Mastodon: 二段階認証のリカバリーコードが再生成されました'
+        title: 二段階認証のリカバリーコードが変更されました
       unlock_instructions:
         subject: 'Mastodon: アカウントのロックの解除'
     omniauth_callbacks:
diff --git a/config/locales/devise.ko.yml b/config/locales/devise.ko.yml
index f48531246..63072340c 100644
--- a/config/locales/devise.ko.yml
+++ b/config/locales/devise.ko.yml
@@ -46,6 +46,18 @@ ko:
         extra: 만약 당신이 시도한 것이 아니라면 이 메일을 무시해 주세요. 위 링크를 클릭해 패스워드를 새로 설정하기 전까지는 패스워드가 바뀌지 않습니다.
         subject: '마스토돈: 패스워드 재설정 방법'
         title: 패스워드 재설정
+      two_factor_disabled:
+        explanation: 당신의 계정에 설정된 이중 인증이 비활성화 되었습니다. 이제 이메일과 비밀번호만으로 로그인이 가능합니다.
+        subject: '마스토돈: 이중 인증 비활성화'
+        title: 2FA 비활성화
+      two_factor_enabled:
+        explanation: 당신의 계정에 이중 인증이 활성화되었습니다. 로그인을 위해 페어링된 T-OTP 앱에서 생성된 토큰이 필요합니다.
+        subject: '마스토돈: 이중 인증 활성화'
+        title: 2FA 활성화
+      two_factor_recovery_codes_changed:
+        explanation: 이전 복구 코드가 무효화되어 새 코드가 생성되었습니다
+        subject: '마스토돈: 이중 인증 복구 코드 재생성됨'
+        title: 2FA 복구 코드 변경됨
       unlock_instructions:
         subject: '마스토돈: 잠금 해제 방법'
     omniauth_callbacks:
diff --git a/config/locales/devise.nl.yml b/config/locales/devise.nl.yml
index 51a95403f..3ab4d9f11 100644
--- a/config/locales/devise.nl.yml
+++ b/config/locales/devise.nl.yml
@@ -46,6 +46,18 @@ nl:
         extra: Wanneer jij dit niet hebt aangevraagd, mag je deze e-mail negeren. Jouw wachtwoord wordt pas gewijzigd nadat je de link hierboven hebt aangeklikt en een nieuw wachtwoord aanmaakt.
         subject: 'Mastodon: Wachtwoord opnieuw instellen'
         title: Wachtwoord opnieuw instellen
+      two_factor_disabled:
+        explanation: Tweestapsverificatie voor jouw account is uitgeschakeld. Je kunt nu alleen inloggen met een e-mailadres en wachtwoord.
+        subject: 'Mastodon: Tweestapsverificatie uitgeschakeld'
+        title: Tweestapsverificatie uitgeschakeld
+      two_factor_enabled:
+        explanation: Tweestapsverificatie voor jouw account is ingeschakeld. Om te kunnen aanmelden is een door een tweestapsverificatie-app genereerde aanmeldcode nodig.
+        subject: 'Mastodon: Tweestapsverificatie ingeschakeld'
+        title: Tweestapsverificatie ingeschakeld
+      two_factor_recovery_codes_changed:
+        explanation: De vorige herstelcodes zijn ongeldig gemaakt en nieuwe zijn aangemaakt.
+        subject: 'Mastodon: Tweestaps-herstelcodes zijn opnieuw aangemaakt'
+        title: Herstelcodes tweestapsverificatie veranderd
       unlock_instructions:
         subject: 'Mastodon: Instructies om opschorten account ongedaan te maken'
     omniauth_callbacks:
diff --git a/config/locales/devise.oc.yml b/config/locales/devise.oc.yml
index 42be33f6b..0fb259429 100644
--- a/config/locales/devise.oc.yml
+++ b/config/locales/devise.oc.yml
@@ -46,6 +46,18 @@ oc:
         extra: S’avètz pas res demandat, fasquètz pas cas a aqueste corrièl. Vòstre senhal cambiarà pas se clicatz pas lo ligam e que ne causissètz pas un novèl.
         subject: Mastodon : consignas per reïnicializar lo senhal
         title: Reïnicializacion del senhal
+      two_factor_disabled:
+        explanation: L’autentificacion dos factors per vòstre compte es estada desactivada. La connexion es ara possibla solament amb l’adreça electronica e lo senhal.
+        subject: 'Mastodon : autentificacion dos factors desactivada'
+        title: 2FA desactivat
+      two_factor_enabled:
+        explanation: L’autentificacion dos factors es estada activada per vòstre compte. La connexion demandarà un geton generat per l’aplicacion TOTP associada.
+        subject: 'Mastodon : autentificacion dos factor activada'
+        title: 2FA activat
+      two_factor_recovery_codes_changed:
+        explanation: Los còdis de recuperacion precedents son ara invalids e de nòus son estats generats.
+        subject: 'Mastodon : còdis de recuperacion dos factors regenerats'
+        title: Còdis 2FA de recuperacion cambiats
       unlock_instructions:
         subject: Mastodon : consignas de desblocatge
     omniauth_callbacks:
diff --git a/config/locales/devise.pt-PT.yml b/config/locales/devise.pt-PT.yml
new file mode 100644
index 000000000..7d3f8fc55
--- /dev/null
+++ b/config/locales/devise.pt-PT.yml
@@ -0,0 +1,83 @@
+---
+pt-PT:
+  devise:
+    confirmations:
+      confirmed: O teu endereço de e-mail foi confirmado com sucesso.
+      send_instructions: Vais receber um email com as instruções para confirmar o teu endereço de email dentro de alguns minutos. Por favor, verifica a caixa de spam se não recebeste o e-mail.
+      send_paranoid_instructions: Se o teu endereço de email já existir na nossa base de dados, vais receber um email com as instruções de confirmação dentro de alguns minutos. Por favor, verifica a caixa de spam se não recebeste o e-mail.
+    failure:
+      already_authenticated: A tua sessão já está aberta.
+      inactive: A tua conta ainda não está ativada.
+      invalid: "%{authentication_keys} ou palavra-passe inválida."
+      last_attempt: Tens mais uma tentativa antes de a tua conta ficar bloqueada.
+      locked: A tua conta está bloqueada.
+      not_found_in_database: "%{authentication_keys} ou palavra-passe inválida."
+      timeout: A tua sessão expirou. Por favor, entra de novo para continuares.
+      unauthenticated: Precisas de entrar na tua conta ou de te registares antes de continuar.
+      unconfirmed: Tens de confirmar o teu endereço de email antes de continuar.
+    mailer:
+      confirmation_instructions:
+        action: Verificar o endereço de e-mail
+        action_with_app: Confirmar e regressar a %{app}
+        explanation: Criaste uma conta em %{host} com este endereço de e-mail. Estás a um clique de activá-la. Se não foste tu que fizeste este registo, por favor ignora esta mensagem.
+        extra_html: Por favor lê <a href="%{terms_path}">as regras da instância</a> e os <a href="%{policy_path}"> nossos termos de serviço</a>.
+        subject: 'Mastodon: Instruções de confirmação %{instance}'
+        title: Verificar o endereço de e-mail
+      email_changed:
+        explanation: 'O e-mail associado à tua conta será alterado para:'
+        extra: Se não alteraste o teu e-mail é possível que alguém tenha conseguido aceder à tua conta. Por favor muda a tua palavra-passe imediatamente ou entra em contato com um administrador do servidor se ficaste sem acesso à tua conta.
+        subject: 'Mastodon: Email alterado'
+        title: Novo endereço de e-mail
+      password_change:
+        explanation: A palavra-passe da tua conta foi alterada.
+        extra: Se não alteraste a tua palavra-passe, é possível que alguém tenha conseguido aceder à tua conta. Por favor muda a tua palavra-passe imediatamente ou entra em contato com um administrador do servidor se ficaste sem acesso à tua conta.
+        subject: 'Mastodon: Nova palavra-passe'
+        title: Palavra-passe alterada
+      reconfirmation_instructions:
+        explanation: Confirma o teu novo endereço para alterar o e-mail.
+        extra: Se esta mudança não foi iniciada por ti, por favor ignora este e-mail. O endereço de e-mail para a tua conta do Mastodon não irá mudar enquanto não acederes ao link acima.
+        subject: 'Mastodon: Confirmação de e-mail %{instance}'
+        title: Validar o endereço de e-mail
+      reset_password_instructions:
+        action: Alterar palavra-passe
+        explanation: Pediste a alteração da palavra-passe da tua conta.
+        extra: Se não fizeste este pedido, por favor ignora este e-mail. A tua palavra-passe não irá mudar se não acederes ao link acima e criares uma nova.
+        subject: 'Mastodon: Instruções para alterar a palavra-passe'
+        title: Solicitar nova palavra-passe
+      unlock_instructions:
+        subject: 'Mastodon: Instruções para desbloquear a tua conta'
+    omniauth_callbacks:
+      failure: Não foi possível autenticar %{kind} porque "%{reason}".
+      success: Autenticado com sucesso na conta %{kind}.
+    passwords:
+      no_token: Não pode aceder a esta página se não vier através do link enviado por email para alteração da sua palavra-passe. Se usaste esse link para chegar aqui, por favor verifica que o endereço URL actual é o mesmo do que foi enviado no email.
+      send_instructions: Vais receber um email com instruções para alterar a palavra-passe dentro de algns minutos.
+      send_paranoid_instructions: Se o teu endereço de email existe na nossa base de dados, vais receber um link para recuperar a palavra-passe dentro de alguns minutos.
+      updated: A tua palavra-passe foi alterada. Estás agora autenticado na tua conta.
+      updated_not_active: A tua palavra-passe foi alterada.
+    registrations:
+      destroyed: Adeus! A tua conta foi cancelada. Esperamos ver-te em breve.
+      signed_up: Bem-vindo! A tua conta foi registada com sucesso.
+      signed_up_but_inactive: A tua conta foi registada. No entanto ainda não está activa.
+      signed_up_but_locked: A tua conta foi registada. No entanto está bloqueada.
+      signed_up_but_unconfirmed: Uma mensagem com um link de confirmação foi enviada para o teu email. Por favor segue esse link para activar a tua conta.
+      update_needs_confirmation: Alteraste o teu endereço de email ou palavra-passe, mas é necessário confirmar essa alteração. Por favor vai ao teu email e segue link que te enviámos.
+      updated: A tua conta foi actualizada com sucesso.
+    sessions:
+      already_signed_out: Sessão encerrada.
+      signed_in: Sessão iniciada.
+      signed_out: Sessão encerrada.
+    unlocks:
+      send_instructions: Vais receber um email com instruções para desbloquear a tua conta dentro de alguns minutos.
+      send_paranoid_instructions: Se a tua conta existe, vais receber um email com instruções a detalhar como a desbloquear dentro de alguns minutos.
+      unlocked: A sua conta foi desbloqueada. Por favor inica uma nova sessão para continuar.
+  errors:
+    messages:
+      already_confirmed: já confirmado, por favor tente iniciar sessão
+      confirmation_period_expired: tem de ser confirmado durante %{period}, por favor tenta outra vez
+      expired: expirou, por favor tente outra vez
+      not_found: não encontrado
+      not_locked: não estava bloqueada
+      not_saved:
+        one: '1 erro impediu este %{resource} de ser guardado:'
+        other: "%{count} erros impediram este %{resource} de ser guardado:"
diff --git a/config/locales/devise.sk.yml b/config/locales/devise.sk.yml
index 4837390db..759d4874b 100644
--- a/config/locales/devise.sk.yml
+++ b/config/locales/devise.sk.yml
@@ -37,7 +37,7 @@ sk:
       reconfirmation_instructions:
         explanation: Potvrď novú emailovú adresu na ktorú chceš zmeniť svoj email.
         extra: Pokiaľ si túto akciu nevyžiadal/a, prosím ignoruj tento email. Emailová adresa pre tvoj Mastodon účet totiž nebude zmenená pokiaľ nepostúpiš na adresu uvedenú vyššie.
-        subject: 'Mastodon: Potvrďenie emailu pre %{instance}'
+        subject: 'Mastodon: Potvrď email pre %{instance}'
         title: Over emailovú adresu
       reset_password_instructions:
         action: Zmeň svoje heslo
diff --git a/config/locales/doorkeeper.ar.yml b/config/locales/doorkeeper.ar.yml
index f443d0dd3..51d8b76b4 100644
--- a/config/locales/doorkeeper.ar.yml
+++ b/config/locales/doorkeeper.ar.yml
@@ -133,7 +133,7 @@ ar:
       read:search: البحث مكانك
       read:statuses: رؤية كافة المنشورات
       write: تغيير كافة بيانات حسابك
-      write:accounts: تعديل ملفك الشخصي
+      write:accounts: تعديل صفحتك التعريفية
       write:blocks: حجب الحسابات و النطاقات
       write:favourites: الإعجاب بمنشورات
       write:filters: إنشاء عوامل تصفية
diff --git a/config/locales/doorkeeper.es-AR.yml b/config/locales/doorkeeper.es-AR.yml
new file mode 100644
index 000000000..515d5c1ed
--- /dev/null
+++ b/config/locales/doorkeeper.es-AR.yml
@@ -0,0 +1 @@
+es-AR:
diff --git a/config/locales/el.yml b/config/locales/el.yml
index acc97d37e..2cafb101d 100644
--- a/config/locales/el.yml
+++ b/config/locales/el.yml
@@ -17,9 +17,6 @@ el:
     contact_unavailable: Μ/Δ
     discover_users: Ανακάλυψε χρήστες
     documentation: Τεκμηρίωση
-    extended_description_html: |
-      <h3>Ένα καλό σημείο για κανόνες</h3>
-      <p>Η αναλυτική περιγραφή δεν έχει ακόμα οριστεί</p>
     federation_hint_html: Με ένα λογαριασμό στο %{instance} θα μπορείς να ακολουθείς ανθρώπους σε οποιοδήποτε κόμβο στο Mastodon αλλά και αλλού.
     generic_description: "%{domain} είναι ένας εξυπηρετητής στο δίκτυο"
     get_apps: Δοκίμασε μια εφαρμογή κινητού
@@ -38,6 +35,9 @@ el:
     status_count_before: Που έγραψαν
     tagline: Ακολούθησε τους γνωστούς σου και ανακάλυψε νέους ανθρώπους
     terms: Όροι χρήσης
+    unavailable_content: Μη διαθέσιμο
+    unavailable_content_description:
+      reason: 'Αιτία:'
     user_count_after:
       one: χρήστης
       other: χρήστες
@@ -225,10 +225,12 @@ el:
       deleted_status: "(διαγραμμένη δημοσίευση)"
       title: Αρχείο ελέγχου
     custom_emojis:
+      assign_category: Κατηγορία
       by_domain: Τομέας
       copied_msg: Επιτυχής δημιουργία τοπικού αντίγραφου του emoji
       copy: Αντιγραφή
       copy_failed_msg: Αδυναμία δημιουργίας τοπικού αντίγραφου αυτού του emoji
+      create_new_category: Νέα κατηγορία
       created_msg: Επιτυχής δημιουργία του emoji!
       delete: Διαγραφή
       destroyed_msg: Επιτυχής καταστροφή του emojo!
@@ -236,6 +238,7 @@ el:
       disabled_msg: Επιτυχής απενεργοποίηση αυτού του emoji
       emoji: Emoji
       enable: Ενεργοποίηση
+      enabled: Ενεργοποιημένα
       enabled_msg: Επιτυχής ενεργοποίηση αυτού του emoji
       image_hint: PNG έως 50KB
       listed: Αναφερθέντα
@@ -245,6 +248,7 @@ el:
       shortcode: Σύντομος κωδικός
       shortcode_hint: Τουλάχιστον 2 χαρακτήρες, μόνο αλφαριθμητικοί και κάτω παύλες
       title: Προσαρμοσμένα emoji
+      uncategorized: Χωρίς κατηγορία
       unlisted: Μη καταχωρημένα
       update_failed_msg: Αδυναμία ενημέρωσης του emoji
       updated_msg: Επιτυχής ενημέρωση του emoji!
@@ -424,6 +428,9 @@ el:
       custom_css:
         desc_html: Τροποποίηση της εμφάνισης μέσω CSS που φορτώνεται σε κάθε σελίδα
         title: Προσαρμοσμένο CSS
+      default_noindex:
+        desc_html: Επηρεάζει όσους χρήστες δεν έχουν αλλάξει αυτή τη ρύθμιση
+        title: Εξαίρεση χρηστών από τις μηχανές αναζήτησης
       domain_blocks:
         all: Για όλους
         disabled: Για κανέναν
@@ -515,6 +522,10 @@ el:
       context: Συνάφεια
       directory: Στον κατάλογο
       in_directory: "%{count} στον κατάλογο"
+      last_active: Τελευταία δραστηριότητα
+      most_popular: Δημοφιλέστερες
+      most_recent: Πιο πρόσφατες
+      name: Ταμπέλα
       review: Κατάσταση έγκρισης
       reviewed: Εγκεκριμένες
       title: Ταμπέλες
@@ -611,6 +622,10 @@ el:
       return: Δείξε το προφίλ του χρήστη
       web: Πήγαινε στο δίκτυο
     title: Ακολούθησε %{acct}
+  challenge:
+    confirm: Συνέχεια
+    invalid_password: Μη έγκυρο συνθηματικό
+    prompt: Επιβεβαίωση συνθηματικού για συνέχεια
   datetime:
     distance_in_words:
       about_x_hours: "%{count}ω"
@@ -626,7 +641,9 @@ el:
       x_months: "%{count}μ"
       x_seconds: "%{count}δ"
   deletes:
+    challenge_not_passed: Τα στοιχεία δεν ήταν σωστά
     confirm_password: Γράψε το τρέχον συνθηματικό σου για να πιστοποιήσεις την ταυτότητά σου
+    confirm_username: Γράψε το όνομα χρήστη σου για επιβεβαίωση
     proceed: Διαγραφή λογαριασμού
     success_msg: Ο λογαριασμός σου διαγράφηκε με επιτυχία
     warning:
@@ -644,23 +661,6 @@ el:
     directory: Κατάλογος λογαριασμών
     explanation: Βρες χρήστες βάσει των ενδιαφερόντων τους
     explore_mastodon: Εξερεύνησε το %{title}
-  domain_blocks:
-    blocked_domains: Λίστα περιορισμένων και αποκλεισμένων τομέων
-    description: Αυτή είναι η λίστα των διακομιστών που ο %{instance} περιορίζει ή απορρίπτει τη σύνδεση μαζί τους.
-    domain: Τομέας
-    media_block: Αποκλεισμός πολυμέσων
-    no_domain_blocks: "(Χωρίς αποκλεισμό πολυμέσων)"
-    severity: Αυστηρότητα
-    severity_legend:
-      media_block: Τα αρχεία πολυμέσων από αυτό τον διακομιστή δεν ανακτώνται, δεν αποθηκεύονται και δεν προβάλλονται στο χρήστη.
-      silence: Οι λογαριασμοί από διακομιστές που έχουν αποσιωπηθεί μπορούν να βρεθούν, να ακολουθηθούν και να δεχτούν αλληλεπιδράσεις αλλά τα τουτ τους δε θα εμφανίζονται στις δημόσιες ροές και οι ειδοποιήσεις τους δε θα παραδίδονται στους τοπικούς χρήστες που δεν τους ακολουθούν.
-      suspension: Κανένα περιεχόμενο ανασταλμένων διακομιστών δεν αποθηκεύεται και δεν εμφανίζεται, ούτε αποστέλλεται σε αυτούς. Οι ενέργειες από τους ανασταλμένους διακομιστές αγνοούνται.
-      suspension_disclaimer: Οι ανασταλμενοι διακομιστές μπορεί περιστασιακά να ανακτήσουν δημόσιο περιεχόμενο από αυτό τον διακομιστή.
-      title: Αυστηρότητες
-    show_rationale: Εμφάνιση αιτιολογίας
-    silence: Αποσιώπηση
-    suspension: Αναστολή
-    title: "%{instance} Λίστα αποκλεισμένων κόμβων"
   domain_validator:
     invalid_domain: δεν είναι έγκυρο όνομα τομέα
   errors:
@@ -694,7 +694,7 @@ el:
     domain_blocks: Μπλοκαρίσματα κόμβων
     follows: Ακολουθείς
     lists: Λίστες
-    mutes: Αποσιωπάς
+    mutes: Αποσιωπήσεις
     storage: Αποθήκευση πολυμέσων
   featured_tags:
     add_new: Προσθήκη νέας
@@ -726,8 +726,9 @@ el:
     all: Όλα
     changes_saved_msg: Οι αλλαγές αποθηκεύτηκαν!
     copy: Αντιγραφή
+    no_batch_actions_available: Δεν υπάρχουν ομαδικές ενέργειες σε αυτή τη σελίδα
     order_by: Ταξινόμηση κατά
-    save_changes: Αποθήκευσε τις αλλαγές
+    save_changes: Αποθήκευση αλλαγών
     validation_errors:
       one: Κάτι δεν είναι εντάξει ακόμα! Για κοίταξε το παρακάτω σφάλμα
       other: Κάτι δεν είναι εντάξει ακόμα! Για κοίταξε τα παρακάτω %{count} σφάλματα
@@ -797,9 +798,10 @@ el:
       too_many: Δεν γίνεται να προσθέσεις περισσότερα από 4 αρχεία
   migrations:
     acct: ΌνομαΧρήστη@Τομέας του νέου λογαριασμού
-    currently_redirecting: 'Το προφίλ σου έχει ρυθμιστεί να ανακατευθύνει στο:'
-    proceed: Αποθήκευση
-    updated_msg: Οι ρυθμίσεις μετακόμισης του λογαριασμού σου ενημερώθηκαν!
+    cancel: Ακύρωση ανακατεύθυνσης
+    errors:
+      not_found: δεν βρέθηκε
+    proceed_with_move: Μετακίνηση ακολούθων
   moderation:
     title: Συντονισμός
   notification_mailer:
@@ -863,7 +865,7 @@ el:
       too_few_options: πρέπει να έχει περισσότερες από μια επιλογές
       too_many_options: δεν μπορεί να έχει περισσότερες από %{max} επιλογές
   preferences:
-    other: Άλλο
+    other: Άλλες
     posting_defaults: Προεπιλογές δημοσίευσης
     public_timelines: Δημόσιες ροές
   relationships:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index c097a7e39..9ca942511 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -17,9 +17,6 @@ en:
     contact_unavailable: N/A
     discover_users: Discover users
     documentation: Documentation
-    extended_description_html: |
-      <h3>A good place for rules</h3>
-      <p>The extended description has not been set up yet.</p>
     federation_hint_html: With an account on %{instance} you'll be able to follow people on any Mastodon server and beyond.
     generic_description: "%{domain} is one server in the network"
     get_apps: Try a mobile app
@@ -38,6 +35,14 @@ en:
     status_count_before: Who authored
     tagline: Follow friends and discover new ones
     terms: Terms of service
+    unavailable_content: Unavailable content
+    unavailable_content_description:
+      domain: Server
+      reason: Reason
+      rejecting_media: 'Media files from these servers will not be processed or stored, and and no thumbnails will be displayed, requiring manual click-through to the original file:'
+      silenced: 'Posts from these servers will be hidden in public timelines and conversations, and no notifications will be generated from their users'' interactions, unless you are following them:'
+      suspended: 'No data from these servers will be processed, stored or exchanged, making any interaction or communication with users from these servers impossible:'
+    unavailable_content_html: Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.
     user_count_after:
       one: user
       other: users
@@ -238,8 +243,10 @@ en:
       disabled_msg: Successfully disabled that emoji
       emoji: Emoji
       enable: Enable
+      enabled: Enabled
       enabled_msg: Successfully enabled that emoji
       image_hint: PNG up to 50KB
+      list: List
       listed: Listed
       new:
         title: Add new custom emoji
@@ -248,12 +255,13 @@ en:
       shortcode_hint: At least 2 characters, only alphanumeric characters and underscores
       title: Custom emojis
       uncategorized: Uncategorized
+      unlist: Unlist
       unlisted: Unlisted
       update_failed_msg: Could not update that emoji
       updated_msg: Emoji successfully updated!
       upload: Upload
     dashboard:
-      authorized_fetch_mode: Authorized fetch mode
+      authorized_fetch_mode: Secure mode
       backlog: backlogged jobs
       config: Configuration
       feature_deletions: Account deletions
@@ -380,6 +388,7 @@ en:
       pending: Waiting for relay's approval
       save_and_enable: Save and enable
       setup: Setup a relay connection
+      signatures_not_enabled: Relays will not work correctly while secure mode or whitelist mode is enabled
       status: Status
       title: Relays
     report_notes:
@@ -563,6 +572,12 @@ en:
     new_trending_tag:
       body: 'The hashtag #%{name} is trending today, but has not been previously reviewed. It will not be displayed publicly unless you allow it to, or just save the form as it is to never hear about it again.'
       subject: New hashtag up for review on %{instance} (#%{name})
+  aliases:
+    add_new: Create alias
+    created_msg: Successfully created a new alias. You can now initiate the move from the old account.
+    deleted_msg: Successfully remove the alias. Moving from that account to this one will no longer be possible.
+    hint_html: If you want to move from another account to this one, here you can create an alias, which is required before you can proceed with moving followers from the old account to this one. This action by itself is <strong>harmless and reversible</strong>. <strong>The account migration is initiated from the old account</strong>.
+    remove: Unlink alias
   appearance:
     advanced_web_interface: Advanced web interface
     advanced_web_interface_hint: 'If you want to make use of your entire screen width, the advanced web interface allows you to configure many different columns to see as much information at the same time as you want: Home, notifications, federated timeline, any number of lists and hashtags.'
@@ -622,6 +637,7 @@ en:
       confirming: Waiting for e-mail confirmation to be completed.
       functional: Your account is fully operational.
       pending: Your application is pending review by our staff. This may take some time. You will receive an e-mail if your application is approved.
+      redirecting_to: Your account is inactive because it is currently redirecting to %{acct}.
     trouble_logging_in: Trouble logging in?
   authorize_follow:
     already_following: You are already following this account
@@ -634,6 +650,11 @@ en:
       return: Show the user's profile
       web: Go to web
     title: Follow %{acct}
+  challenge:
+    confirm: Continue
+    hint_html: "<strong>Tip:</strong> We won't ask you for your password again for the next hour."
+    invalid_password: Invalid password
+    prompt: Confirm password to continue
   datetime:
     distance_in_words:
       about_x_hours: "%{count}h"
@@ -669,23 +690,6 @@ en:
     directory: Profile directory
     explanation: Discover users based on their interests
     explore_mastodon: Explore %{title}
-  domain_blocks:
-    blocked_domains: List of limited and blocked domains
-    description: This is the list of servers that %{instance} limits or reject federation with.
-    domain: Domain
-    media_block: Media block
-    no_domain_blocks: "(No domain blocks)"
-    severity: Severity
-    severity_legend:
-      media_block: Media files coming from the server are neither fetched, stored, or displayed to the user.
-      silence: Accounts from silenced servers can be found, followed and interacted with, but their toots will not appear in the public timelines, and notifications from them will not reach local users who are not following them.
-      suspension: No content from suspended servers is stored or displayed, nor is any content sent to them. Interactions from suspended servers are ignored.
-      suspension_disclaimer: Suspended servers may occasionally retrieve public content from this server.
-      title: Severities
-    show_rationale: Show rationale
-    silence: Silence
-    suspension: Suspension
-    title: "%{instance} List of blocked instances"
   domain_validator:
     invalid_domain: is not a valid domain name
   errors:
@@ -823,10 +827,35 @@ en:
       images_and_video: Cannot attach a video to a status that already contains images
       too_many: Cannot attach more than 4 files
   migrations:
-    acct: username@domain of the new account
-    currently_redirecting: 'Your profile is set to redirect to:'
-    proceed: Save
-    updated_msg: Your account migration setting successfully updated!
+    acct: Moved to
+    cancel: Cancel redirect
+    cancel_explanation: Cancelling the redirect will re-activate your current account, but will not bring back followers that have been moved to that account.
+    cancelled_msg: Successfully cancelled the redirect.
+    errors:
+      already_moved: is the same account you have already moved to
+      missing_also_known_as: is not back-referencing this account
+      move_to_self: cannot be current account
+      not_found: could not be found
+      on_cooldown: You are on cooldown
+    followers_count: Followers at time of move
+    incoming_migrations: Moving from a different account
+    incoming_migrations_html: To move from another account to this one, first you need to <a href="%{path}">create an account alias</a>.
+    moved_msg: Your account is now redirecting to %{acct} and your followers are being moved over.
+    not_redirecting: Your account is not redirecting to any other account currently.
+    on_cooldown: You have recently migrated your account. This function will become available again in %{count} days.
+    past_migrations: Past migrations
+    proceed_with_move: Move followers
+    redirecting_to: Your account is redirecting to %{acct}.
+    set_redirect: Set redirect
+    warning:
+      backreference_required: The new account must first be configured to back-reference this one
+      before: 'Before proceeding, please read these notes carefully:'
+      cooldown: After moving there is a cooldown period during which you will not be able to move again
+      disabled_account: Your current account will not be fully usable afterwards. However, you will have access to data export as well as re-activation.
+      followers: This action will move all followers from the current account to the new account
+      only_redirect_html: Alternatively, you can <a href="%{path}">only put up a redirect on your profile</a>.
+      other_data: No other data will be moved automatically
+      redirect: Your current account's profile will be updated with a redirect notice and be excluded from searches
   moderation:
     title: Moderation
   notification_mailer:
@@ -972,6 +1001,7 @@ en:
   settings:
     account: Account
     account_settings: Account settings
+    aliases: Account aliases
     appearance: Appearance
     authorized_apps: Authorized apps
     back: Back to Mastodon
@@ -1015,6 +1045,9 @@ en:
       private: Non-public toot cannot be pinned
       reblog: A boost cannot be pinned
     poll:
+      total_people:
+        one: "%{count} person"
+        other: "%{count} people"
       total_votes:
         one: "%{count} vote"
         other: "%{count} votes"
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index b5b8656a4..6a9dff66b 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -1,7 +1,7 @@
 ---
 eo:
   about:
-    about_hashtag_html: Ĉi tiuj estas la publikaj fajfoj markitaj per <strong>#%{hashtag}</strong>. Vi povas interagi kun ili se vi havas konton ie ajn en la fediverse.
+    about_hashtag_html: Ĉi tiuj estas la publikaj mesaĝoj markitaj per <strong>#%{hashtag}</strong>. Vi povas interagi kun ili se vi havas konton ie ajn en la fediverse.
     about_mastodon_html: Mastodon estas socia reto bazita sur malfermitaj retaj protokoloj kaj sur libera malfermitkoda programo. Ĝi estas sencentra kiel retmesaĝoj.
     about_this: Pri
     active_count_after: aktiva
@@ -17,13 +17,13 @@ eo:
     contact_unavailable: Ne disponebla
     discover_users: Malkovri uzantojn
     documentation: Dokumentado
-    extended_description_html: |
-      <h3>Bona loko por reguloj</h3>
-      <p>La detala priskribo ne estis elektita.</p>
     federation_hint_html: Per konto ĉe %{instance}, vi povos sekvi homojn ĉe iu ajn Mastodon nodo kaj preter.
     generic_description: "%{domain} estas unu servilo en la reto"
     get_apps: Provu telefonan aplikaĵon
     hosted_on: "%{domain} estas nodo de Mastodon"
+    instance_actor_flash: |
+      Ĉi tiu konto estas virtuala ulo uzata por reprezenti la servilon mem kaj ne iun apartan uzanton.
+      Ĝi estas uzata por frataraj celoj kaj ĝi ne devus esti blokita krom se vi volas bloki la tutan servilon, tiuokaze vi devus uzi domajnan blokadon.
     learn_more: Lerni pli
     privacy_policy: Privateca politiko
     see_whats_happening: Vidi kio okazas
@@ -35,6 +35,9 @@ eo:
     status_count_before: Kie skribiĝis
     tagline: Sekvi amikojn kaj trovi novan onin
     terms: Uzkondiĉoj
+    unavailable_content: Nedisponebla enhavo
+    unavailable_content_description:
+      reason: 'Kialo:'
     user_count_after:
       one: uzanto
       other: uzantoj
@@ -485,7 +488,7 @@ eo:
       back_to_account: Reveni al konta paĝo
       batch:
         delete: Forigi
-        nsfw_off: Marki ne tikla
+        nsfw_off: Marki netikla
         nsfw_on: Marki tikla
       deleted: Forigita
       failed_to_execute: Ekigo malsukcesa
@@ -499,6 +502,9 @@ eo:
       context: Kunteksto
       directory: En la adresaro
       in_directory: "%{count} en adresaro"
+      last_active: Lasta aktiva
+      most_recent: Plej lasta
+      name: Kradvorto
       review: La statuso de la recenzo
       reviewed: Recenzis
       title: Kradvortoj
@@ -524,8 +530,10 @@ eo:
       subject: Nova kradvorto kontrolebla en %{instance} (#%{name})
   appearance:
     advanced_web_interface: Altnivela retpaĝa interfaco
+    advanced_web_interface_hint: 'Se vi volas uzi la tutan larĝecon de via ekrano, la kompleksa reta interfaco permesas al vi agordi multajn malsamajn kolumnojn por vidi tiom da informoj kiom vi volas samtempe: Hejmo, sciigoj, fratara tempolinio, kaj ajna kvanto de listoj kaj kradvortoj.'
     animations_and_accessibility: Animacioj kaj alirebleco
     confirmation_dialogs: Konfirmaj fenestroj
+    discovery: Eltrovo
     sensitive_content: Tikla enhavo
   application_mailer:
     notification_preferences: Ŝanĝi retmesaĝajn preferojn
@@ -548,6 +556,8 @@ eo:
     checkbox_agreement_html: Mi samopinii al la <a href="%{rules_path}" target="_blank">Servo reguloj</a> kaj <a href="%{terms_path}" target="_blank">kondiĉo al servadon</a>
     delete_account: Forigi konton
     delete_account_html: Se vi deziras forigi vian konton, vi povas <a href="%{path}">fari tion ĉi tie</a>. Vi bezonos konfirmi vian peton.
+    description:
+      prefix_sign_up: Registriĝi ĉe Mastodon hodiaŭ!
     didnt_get_confirmation: Ĉu vi ne ricevis la instrukciojn por konfirmi?
     forgot_password: Pasvorto forgesita?
     invalid_reset_password_token: Ĵetono por restarigi pasvorton nevalida aŭ eksvalida. Bonvolu peti novan.
@@ -582,6 +592,10 @@ eo:
       return: Montri la profilon de la uzanto
       web: Iri al reto
     title: Sekvi %{acct}
+  challenge:
+    confirm: Daŭrigi
+    invalid_password: Nevalida pasvorto
+    prompt: Konfirmi pasvorton por daŭrigi
   datetime:
     distance_in_words:
       about_x_hours: "%{count}h"
@@ -604,10 +618,6 @@ eo:
     directory: Profilujo
     explanation: Malkovru uzantojn per iliaj interesoj
     explore_mastodon: Esplori %{title}
-  domain_blocks:
-    domain: Domajno
-    no_domain_blocks: "(Nenio domajna blokado)"
-    silence: Silenta
   domain_validator:
     invalid_domain: ne estas valida domajna nomo
   errors:
@@ -649,6 +659,7 @@ eo:
     add_new: Aldoni novan
     errors:
       limit: Vi jam elstarigis la maksimuman kvanton da kradvortoj
+    hint_html: "<strong>Kio estas la trajtaj kradvortoj?</strong> Ili bone videblas en via publika profilo kaj permesas al homoj trarigardi viajn publikajn mesaĝojn specife laŭ tiuj kradvortoj. Ili estas bonaj iloj por sekvi la evoluon de kreadaj laboroj aŭ longdaŭraj projektoj."
   filters:
     contexts:
       home: Hejma templinio
@@ -680,7 +691,7 @@ eo:
       one: Io mise okazis! Bonvolu konsulti la suban erar-raporton
       other: Io mise okazis! Bonvolu konsulti la subajn %{count} erar-raportojn
   html_validator:
-    invalid_markup: 'havas malvalida HTML markado: %{error}'
+    invalid_markup: 'havas nevalidan HTML-markadon: %{error}'
   identity_proofs:
     active: Aktiva
     authorize: Jes, permesi
@@ -745,9 +756,6 @@ eo:
       too_many: Aldoni pli ol 4 dosierojn ne eblas
   migrations:
     acct: uzantnomo@domajno de la nova konto
-    currently_redirecting: 'Via profilo alidirektos al:'
-    proceed: Konservi
-    updated_msg: Via agordo pri konta migrado estis sukcese ĝisdatigita!
   moderation:
     title: Kontrolado
   notification_mailer:
diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml
new file mode 100644
index 000000000..fe61b69c4
--- /dev/null
+++ b/config/locales/es-AR.yml
@@ -0,0 +1,20 @@
+---
+es-AR:
+  errors:
+    '400': The request you submitted was invalid or malformed.
+    '403': You don't have permission to view this page.
+    '404': The page you are looking for isn't here.
+    '406': This page is not available in the requested format.
+    '410': The page you were looking for doesn't exist here anymore.
+    '422': 
+    '429': Throttled
+    '500': 
+    '503': The page could not be served due to a temporary server failure.
+  invites:
+    expires_in:
+      '1800': 30 minutes
+      '21600': 6 hours
+      '3600': 1 hour
+      '43200': 12 hours
+      '604800': 1 week
+      '86400': 1 day
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 892d82e9c..ef22c7b82 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -17,9 +17,6 @@ es:
     contact_unavailable: N/A
     discover_users: Descubrir usuarios
     documentation: Documentación
-    extended_description_html: |
-      <h3>Un buen lugar para las reglas</h3>
-      <p>La descripción extendida no se ha colocado aún.</p>
     federation_hint_html: Con una cuenta en %{instance} usted podrá seguir a las personas en cualquier servidor de Mastodon y más allá.
     generic_description: "%{domain} es un servidor en la red"
     get_apps: Probar una aplicación móvil
@@ -38,6 +35,13 @@ es:
     status_count_before: Qué han escrito
     tagline: Seguir a amigos existentes y descubre nuevos
     terms: Condiciones de servicio
+    unavailable_content: Contenido no disponible
+    unavailable_content_description:
+      reason: 'Motivo:'
+      rejecting_media: Los archivos multimedia de este servidor no serán procesados y no se mostrarán miniaturas, lo que requiere un clic manual en el otro servidor.
+      silenced: Las publicaciones de este servidor no se mostrarán en ningún lugar salvo en el Inicio si sigues al autor.
+      suspended: No podrás seguir a nadie de este servidor, y ningún dato de este será procesado o almacenado, y no se intercambiarán datos.
+    unavailable_content_html: Mastodon generalmente le permite ver contenido e interactuar con usuarios de cualquier otro servidor en el fediverso. Estas son las excepciones que se han hecho en este servidor en particular.
     user_count_after:
       one: usuario
       other: usuarios
@@ -45,6 +49,8 @@ es:
     what_is_mastodon: "¿Qué es Mastodon?"
   accounts:
     choices_html: 'Elecciones de %{name}:'
+    endorsements_hint: Puedes recomendar a gente que sigues desde la interfaz web, y aparecerán allí.
+    featured_tags_hint: Puede presentar hashtags específicos que se mostrarán aquí.
     follow: Seguir
     followers:
       one: Seguidor
@@ -228,6 +234,7 @@ es:
       copied_msg: Copia local del emoji creada con éxito
       copy: Copiar
       copy_failed_msg: No se pudo realizar una copia local de ese emoji
+      create_new_category: Crear una nueva categoría
       created_msg: "¡Emoji creado con éxito!"
       delete: Borrar
       destroyed_msg: "¡Emojo destruido con éxito!"
@@ -423,6 +430,9 @@ es:
       custom_css:
         desc_html: Modificar el aspecto con CSS cargado en cada página
         title: CSS personalizado
+      domain_blocks:
+        all: A todos
+        disabled: A nadie
       hero:
         desc_html: Mostrado en la página principal. Recomendable al menos 600x100px. Por defecto se establece a la miniatura de la instancia
         title: Imagen de portada
@@ -506,6 +516,10 @@ es:
       context: Contexto
       directory: En el directorio
       in_directory: "%{count} en el directorio"
+      last_active: Última actividad
+      most_popular: Más popular
+      most_recent: Más reciente
+      name: Hashtag
       review: Estado de revisión
       reviewed: Revisado
       title: Etiquetas
@@ -598,6 +612,8 @@ es:
       return: Regresar al perfil del usuario
       web: Ir al sitio web
     title: Seguir a %{acct}
+  challenge:
+    confirm: Continuar
   datetime:
     distance_in_words:
       about_x_hours: "%{count}h"
@@ -620,8 +636,6 @@ es:
     directory: Directorio de perfiles
     explanation: Descubre usuarios según sus intereses
     explore_mastodon: Explorar %{title}
-  domain_blocks:
-    domain: Dominio
   domain_validator:
     invalid_domain: no es un nombre de dominio válido
   errors:
@@ -757,9 +771,6 @@ es:
       too_many: No se pueden adjuntar más de 4 archivos
   migrations:
     acct: username@domain de la nueva cuenta
-    currently_redirecting: 'Tu perfil está redireccionado a:'
-    proceed: Guardar
-    updated_msg: "¡La configuración de migración de tu cuenta  ha sido actualizada con éxito!"
   moderation:
     title: Moderación
   notification_mailer:
diff --git a/config/locales/et.yml b/config/locales/et.yml
index 7d0771983..0a66d49f4 100644
--- a/config/locales/et.yml
+++ b/config/locales/et.yml
@@ -17,9 +17,6 @@ et:
     contact_unavailable: Pole saadaval
     discover_users: Avasta kasutajaid
     documentation: Dokumentatsioon
-    extended_description_html: |
-      <h3>Hea koht reeglite jaoks</h3>
-      <p>Laiendatud kirjeldus pole veel üles seadistatud.</p>
     federation_hint_html: Kui Teil on kasutaja %{instance}-is, saate Te jälgida inimesi üks kõik millisel Mastodoni serveril ja kaugemalgi.
     generic_description: "%{domain} on ainult üks server terves võrgus"
     get_apps: Proovi mobiilirakendusi
@@ -724,9 +721,6 @@ et:
       too_many: Ei saa lisada rohkem, kui 4 faili
   migrations:
     acct: uue konto kasutajanimi@domeen
-    currently_redirecting: 'Teie profiil on sätestatud suunama ümber:'
-    proceed: Salvesta
-    updated_msg: Teie konto migreerumissätete uuendamine õnnestus!
   moderation:
     title: Moderatsioon
   notification_mailer:
diff --git a/config/locales/eu.yml b/config/locales/eu.yml
index 2a4d61296..a3061b99e 100644
--- a/config/locales/eu.yml
+++ b/config/locales/eu.yml
@@ -17,9 +17,6 @@ eu:
     contact_unavailable: E/E
     discover_users: Aurkitu erabiltzaileak
     documentation: Dokumentazioa
-    extended_description_html: |
-      <h3>Arauentzako toki egoki bat</h3>
-      <p>Azalpen luzea ez da ezarri oraindik.</p>
     federation_hint_html: "%{instance} instantzian kontu bat izanda edozein Mastodon zerbitzariko jendea jarraitu ahal izango duzu, eta harago ere."
     generic_description: "%{domain} sareko zerbitzari bat da"
     get_apps: Probatu mugikorrerako aplikazio bat
@@ -618,10 +615,6 @@ eu:
     directory: Profilen direktorioa
     explanation: Deskubritu erabiltzaileak interesen arabera
     explore_mastodon: Esploratu %{title}
-  domain_blocks:
-    domain: Domeinua
-    severity: Larritasuna
-    silence: Isilarazi
   domain_validator:
     invalid_domain: ez da domeinu izen baliogarria
   errors:
@@ -757,9 +750,6 @@ eu:
       too_many: Ezin dira 4 fitxategi baino gehiago erantsi
   migrations:
     acct: Kontu berriaren erabiltzaile@domeinua
-    currently_redirecting: 'Zure profila hona birbideratzeko ezarri da:'
-    proceed: Gorde
-    updated_msg: Kontuaren migrazio-ezarpenak ongi eguneratu dira!
   moderation:
     title: Moderazioa
   notification_mailer:
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index 7f316c784..0aa8b7a51 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -10,16 +10,13 @@ fa:
     api: رابط برنامه‌نویسی کاربردی
     apps: اپ‌های موبایل
     apps_platforms: ماستدون را در iOS، اندروید، و سایر سیستم‌ها داشته باشید
-    browse_directory: در فهرست گزیدهٔ کاربران این سرور چرخی بزنید و کاربران را بر اساس علاقه‌مندی‌هایشان پیدا کنید
+    browse_directory: کاربران این سرور را بر اساس علاقه‌مندی‌هایشان پیدا کنید
     browse_public_posts: فهرست لحظه‌ای نوشته‌های عمومی در ماستدون را ببینید
     contact: تماس
     contact_missing: تعیین نشده
     contact_unavailable: موجود نیست
     discover_users: یافتن کاربران
     documentation: مستندات
-    extended_description_html: |
-      <h3>جای خوبی برای قانون‌ها</h3>
-      <p>توضیحات تکمیلی نوشته نشده است.</p>
     federation_hint_html: با داشتن حساب روی %{instance} می‌توانید کاربران همهٔ سرورهای دیگر ماستدون (و سایر شبکه‌های سازگار با آن) را پی بگیرید.
     generic_description: "%{domain} یک سرور روی شبکه است"
     get_apps: یک اپ موبایل را امتحان کنید
@@ -38,6 +35,13 @@ fa:
     status_count_before: که در کنار هم
     tagline: با دوستان خود در ارتباط باشید و دوستان تازه پیدا کنید
     terms: شرایط کاربری
+    unavailable_content: محتوای ناموجود
+    unavailable_content_description:
+      reason: 'دلیل:'
+      rejecting_media: تصاویر فرستاده شده از سمت این سرور پردازش نخواهد شد و هیچ تصویر کوچکی از آن‌ها در این‌جا نمایش نخواهد یافت، و آن‌ها را باید مستقیماً در آن سرور ببینید.
+      silenced: هیچ کدام از نوشته‌ها از طرف این سرور این‌جا نمایش نخواهند یافت مگر در فهرست پیگیری‌ها شما، اگر نویسنده‌اش را پی بگیرید.
+      suspended: شما نمی‌توانید هیچ کدام از کاربرهای این سرور را پی بگیرید، و هیچ داده‌ای از طرف این سرور پردازش یا ذخیره یا مبادله نخواهد شد.
+    unavailable_content_html: ماستدون در حالت کلی اجازه می‌دهد که شما همهٔ مطالب و کاربران در سرورهای دیگر را نیز ببینید و با آن‌ها برهم‌کنش داشته باشید. فهرست زیر ولی استثناهای این ارتباط است که به طور خاص روی این سرور اعمال شده‌اند.
     user_count_after:
       one: کاربر
       other: کاربر
@@ -58,6 +62,7 @@ fa:
     media: عکس و ویدیو
     moved_html: "%{name} حساب خود را به %{new_profile_link} منتقل کرده است:"
     network_hidden: این اطلاعات در دسترس نیست
+    never_active: هرگز
     nothing_here: این‌جا چیزی نیست!
     people_followed_by: کسانی که %{name} پی می‌گیرد
     people_who_follow: کسانی که %{name} را پی می‌گیرند
@@ -224,10 +229,12 @@ fa:
       deleted_status: "(بوق پاک‌شده)"
       title: سیاههٔ بازرسی
     custom_emojis:
+      assign_category: تعیین دسته
       by_domain: دامین
       copied_msg: نسخهٔ محلی شکلک با موفقیت ساخته شد
       copy: نسخه‌برداری
       copy_failed_msg: نشد که نسخهٔ محلی این شکلک ساخته شود
+      create_new_category: ساختن دستهٔ تازه
       created_msg: این شکلک با موفقیت ساخته شد!
       delete: پاک کردن
       destroyed_msg: این شکلک با موفقیت پاک شد!
@@ -235,8 +242,10 @@ fa:
       disabled_msg: این شکلک با موفقیت غیرفعال شد
       emoji: شکلک
       enable: فعال‌سازی
+      enabled: فعال
       enabled_msg: این شکلک با موفقیت فعال شد
       image_hint: پروندهٔ PNG حداکثر 50KB
+      list: فهرست
       listed: فهرست‌شده
       new:
         title: افزودن شکلک سفارشی
@@ -244,11 +253,14 @@ fa:
       shortcode: کد کوتاه
       shortcode_hint: دست‌کم ۲ نویسه و تنها شامل حروف، اعداد و زیرخط
       title: شکلک‌های سفارشی
+      uncategorized: دسته‌بندی نشده
+      unlist: نافهرست
       unlisted: فهرست‌نشده
       update_failed_msg: این شکلک نتوانست به‌روز شود
       updated_msg: شکلک با موفقیت به‌روز شد!
       upload: بارگذاری
     dashboard:
+      authorized_fetch_mode: حالت دریافت مجازشده
       backlog: کارهای باقیمانده
       config: پیکربندی
       feature_deletions: حساب‌های حذف‌شده
@@ -374,6 +386,7 @@ fa:
       pending: در انتظار پذیرش رله
       save_and_enable: ذخیره و فعال‌سازی
       setup: پیوستن به رله‌ها
+      signatures_not_enabled: وقتی حالت امن یا حالت فهرست سفید فعال باشد رله‌ها به درستی کار نخواهند کرد
       status: وضعیت
       title: رله‌ها
     report_notes:
@@ -422,6 +435,9 @@ fa:
       custom_css:
         desc_html: ظاهر ماستدون را با CSS-ای که در همهٔ صفحه‌ها جاسازی می‌شود تغییر دهید
         title: سبک CSS سفارشی
+      default_noindex:
+        desc_html: روی همهٔ کاربرانی که این تنظیم را خودشان تغییر نداده‌اند تأثیر می‌گذارد
+        title: درخواست پیش‌فرض از طرف کاربران برای ظاهر نشدن در نتایج موتورهای جستجوگر
       domain_blocks:
         all: برای همه
         disabled: برای هیچ‌کدام
@@ -513,6 +529,10 @@ fa:
       context: زمینه
       directory: در فهرست
       in_directory: "%{count} در فهرست"
+      last_active: آخرین فعالیت
+      most_popular: محبوب‌ترین
+      most_recent: تازه‌ترین
+      name: برچسب
       review: وضعیت بازبینی
       reviewed: بازبینی شده
       title: برچسب‌ها
@@ -538,6 +558,12 @@ fa:
     new_trending_tag:
       body: 'برچسب #%{name} امروز پرطرفدار است، ولی تا حالا بازبینی نشده. تا وقتی که شما اجازه نداده‌اید، این برچسب به طور عمومی نمایش داده نخواهد شد. اگر فرم را به شکل فعلی ذخیره کنید، هیچ وقت چیزی دربارهٔ این برچسب نخواهید دید.'
       subject: برچسب تازه‌ای در %{instance} نیازمند بررسی است (#%{name})
+  aliases:
+    add_new: ساختن نام مستعار
+    created_msg: نام مستعار تازه با موفقیت ساخته شد. الان می‌توانید انتقال از حساب قدیمی را آغاز کنید.
+    deleted_msg: نام مستعار با موفقیت حذف شد. انتقال از آن حساب به حساب فعلی دیگر ممکن نیست.
+    hint_html: اگر می‌خواهید از حساب دیگری به این حساب منتقل شوید، این‌جا می‌توانید یک نام مستعار بسازید که برای انتقال از حساب قدیمی به این حساب لازم است. این کار به تنهایی <strong>بی‌ضرر و قابل بازگشت</strong> است. <strong>فرایند انتقال حساب از حساب قدیمی آغاز خواهد شد</strong>.
+    remove: حذف ارتباط نام مستعار
   appearance:
     advanced_web_interface: رابط کاربری پیشرفته
     advanced_web_interface_hint: 'اگر می‌خواهید همهٔ فضای نمایشگر خود را به کار ببرید، می‌توانید به کمک رابط کاربری پیشرفته ستون‌های گوناگونی داشته باشید تا در یک نگاه همهٔ اطلاعاتی را که می‌خواهید ببینید: نوشته‌های دیگران، اعلان‌ها، فهرست نوشته‌های همه‌جا، و هر تعداد فهرست و برچسب که بخواهید.'
@@ -567,6 +593,10 @@ fa:
     checkbox_agreement_without_rules_html: من با <a href="%{terms_path}" target="_blank">شرایط استفاده</a> موافقم
     delete_account: پاک‌کردن حساب
     delete_account_html: اگر می‌خواهید حساب خود را پاک کنید، از <a href="%{path}">این‌جا</a> پیش بروید. از شما درخواست تأیید خواهد شد.
+    description:
+      prefix_invited_by_user: "@%{name} شما را به عضویت در این سرور ماستدون دعوت کرده است!"
+      prefix_sign_up: همین امروز عضو ماستدون شوید!
+      suffix: با داشتن حساب می‌توانید دیگران را پی بگیرید، نوشته‌های تازه منتشر کنید، و با کاربران دیگر از هر سرور ماستدون دیگری و حتی سرورهای دیگر در ارتباط باشید!
     didnt_get_confirmation: راهنمایی برای تأیید را دریافت نکردید؟
     forgot_password: رمزتان را گم کرده‌اید؟
     invalid_reset_password_token: کد بازنشانی رمز نامعتبر یا منقضی شده است. لطفاً کد دیگری درخواست کنید.
@@ -593,6 +623,7 @@ fa:
       confirming: در حال انتظار برای کامل شدن تأیید ایمیل.
       functional: حساب شما قابل استفاده است.
       pending: درخواست شما منتظر تأیید مسئولان سایت است و این فرایند ممکن است کمی طول بکشد. اگر درخواست شما پذیرفته شود به شما ایمیلی فرستاده خواهد شد.
+      redirecting_to: حساب شما غیرفعال است زیرا هم‌اکنون به %{acct} منتقل شده است.
     trouble_logging_in: برای ورود مشکلی دارید؟
   authorize_follow:
     already_following: شما همین الان هم این حساب را پی‌می‌گیرید
@@ -605,6 +636,11 @@ fa:
       return: نمایهٔ این کاربر را نشان بده
       web: رفتن به وب
     title: پیگیری %{acct}
+  challenge:
+    confirm: ادامه
+    hint_html: "<strong>نکته:</strong> ما در یک ساعت آینده رمزتان را از شما نخواهیم پرسید."
+    invalid_password: رمز نامعتبر
+    prompt: برای ادامه رمزتان را تأیید کنید
   datetime:
     distance_in_words:
       about_x_hours: "%{count} ساعت"
@@ -620,20 +656,33 @@ fa:
       x_months: "%{count} ماه"
       x_seconds: "%{count} ثانیه"
   deletes:
+    challenge_not_passed: اطلاعاتی که وارد کردید اشتباه بود
     confirm_password: رمز فعلی خود را وارد کنید تا معلوم شود که خود شمایید
+    confirm_username: برای تأیید این فرایند نام کاربری خود را وارد کنید
     proceed: پاک‌کردن حساب
     success_msg: حساب شما با موفقیت پاک شد
+    warning:
+      before: 'پیش از ادامه،‌ لطفاً نکته‌های زیر را به دقت بخوانید:'
+      caches: محتواهایی که سرورهای دیگر ذخیره کرده‌اند شاید همچنان باقی بمانند
+      data_removal: نوشته‌ها و داده‌های شما برای همیشه پاک خواهند شد
+      email_change_html: شما می‌توانید بدون پاک کردن حساب <a href="%{path}">نشانی ایمیل خود را تغییر دهید</a>
+      email_contact_html: اگر ایمیل همچنان نرسیده، برای درخواست کمک به <a href="mailto:%{email}">%{email}</a> پیغام دهید
+      email_reconfirmation_html: اگر ایمیل تأیید به دستتان نرسیده، می‌توانید <a href="%{path}">یک بار دیگر برایش درخواست بدهید</a>
+      irreversible: شما نخواهید توانست حساب خود را بازیابی یا فعال‌سازی کنید
+      more_details_html: برای اطلاعات بیشتر <a href="%{terms_path}">سیاست رازداری</a> را ببینید.
+      username_available: نام کاربری شما دوباره در دسترس خواهد بود
+      username_unavailable: نام کاربری شما برای دیگران غیرقابل دسترس خواهد ماند
   directories:
     directory: فهرست گزیدهٔ کاربران
     explanation: کاربران این سرور را بر اساس علاقه‌مندی‌هایشان پیدا کنید
     explore_mastodon: گشت و گذار در %{title}
-  domain_blocks:
-    blocked_domains: فهرست دامین‌های محدود یا مسدود
+  domain_validator:
+    invalid_domain: نام دامین معتبر نیست
   errors:
-    '400': The request you submitted was invalid or malformed.
+    '400': درخواستی که فرستادید نامعتبر یا اشتباه بود.
     '403': شما اجازهٔ دیدن این صفحه را ندارید.
     '404': صفحه‌ای که به دنبالش هستید این‌جا نیست.
-    '406': This page is not available in the requested format.
+    '406': این صفحه در قالبی که درخواست کرده‌اید موجود نیست.
     '410': صفحه‌ای که به دنبالش بودید دیگر این‌جا وجود ندارد.
     '422':
       content: تأیید امنیتی انجام نشد. آیا مرورگر شما کوکی‌ها را مسدود می‌کند؟
@@ -642,7 +691,7 @@ fa:
     '500':
       content: شرمنده، یک چیزی از سمت ما اشتباه شده.
       title: این صفحه درست نیست
-    '503': The page could not be served due to a temporary server failure.
+    '503': این صفحه به خاطر مشکل موقت سرور در دسترس نیست.
     noscript_html: برای استفاده از نسخهٔ تحت وب ماستدون، لطفاً جاوااسکریپت را فعال کنید. یا به جایش می‌توانید <a href="%{apps_path}">یک اپ ماستدون</a> را به‌کار ببرید.
   existing_username_validator:
     not_found: کاربری در این سرور با این نام کاربری پیدا نشد
@@ -666,6 +715,7 @@ fa:
     add_new: افزودن تازه
     errors:
       limit: شما بیشترین تعداد مجاز برچسب‌ها را دارید
+    hint_html: "<strong>برچسب‌های برگزیده چیستند؟</strong> این برچسب‌ها (هشتگ‌ها) به طور واضحی روی نمایهٔ عمومی شما نمایش می‌یابند و دیگران می‌توانند نوشته‌های شما را تحت هر کدام از این برچسب‌ها مرور کنند. این یک روش بسیار خوب برای دسته‌بندی آثار خلاقانه یا پروژه‌های بلندمدت شماست."
   filters:
     contexts:
       home: خانه
@@ -686,10 +736,12 @@ fa:
     developers: برنامه‌نویسان
     more: بیشتر…
     resources: منابع
+    trending_now: پرطرفدار
   generic:
     all: همه
     changes_saved_msg: تغییرات با موفقیت ذخیره شدند!
     copy: رونوشت
+    no_batch_actions_available: هیچ کار گروهی‌ای در این صفحه موجود نیست
     order_by: مرتب‌سازی
     save_changes: ذخیرهٔ تغییرات
     validation_errors:
@@ -761,9 +813,31 @@ fa:
       too_many: نمی‌توان بیشتر از ۴ تصویر بارگذاری کرد
   migrations:
     acct: username@domain حساب تازه
-    currently_redirecting: 'نمایهٔ شما منتقل می‌شود به:'
-    proceed: ذخیره
-    updated_msg: تنظیمات نقل مکان حساب شما با موفقیت به‌روز شد!
+    cancel: لغو انتقال
+    cancel_explanation: با لغو انتقال، حساب شما دوباره فعال می‌شود، ولی این کار پیگیران شما را که به حساب دیگر منتقل شده‌اند برنمی‌گرداند.
+    cancelled_msg: انتقال حساب با موفقیت لغو شد.
+    errors:
+      already_moved: این همان حسابی است که به آن منتقل شده‌اید
+      missing_also_known_as: به حساب شما اشاره نمی‌کند
+      move_to_self: نمی‌تواند حساب فعلی شما باشد
+      not_found: چنین حسابی پیدا نشد
+      on_cooldown: شما باید صبر کنید
+    followers_count: شمار پیگیران در زمان انتقال
+    incoming_migrations: انتقال از یک حساب دیگر
+    incoming_migrations_html: برای انتقال از یک حساب دیگر به این حساب، شما باید نخست <a href="%{path}">یک نام مستعار بسازید</a>.
+    moved_msg: حساب شما هم‌اینک به %{acct} منتقل شده است و پیگیران شما در حال انتقال به آن‌جا هستند.
+    not_redirecting: حساب شما هم‌اینک به هیچ حساب دیگری منتقل نشده است یا اشاره نمی‌کند.
+    on_cooldown: شما به تازگی حساب خود را منتقل کرده‌اید. این ویژگی برای شما دوباره در %{count} روز فعال خواهد شد.
+    past_migrations: انتقال‌های پیشین
+    proceed_with_move: انتقال پیگیران
+    redirecting_to: حساب شما هم‌اینک به %{acct} منتقل شده است.
+    warning:
+      backreference_required: حساب تازهٔ شما نخست باید تنظیم شود تا به این حساب اشاره کند
+      before: 'پیش از ادامه،‌ لطفاً نکته‌های زیر را به دقت بخوانید:'
+      cooldown: پس از انتقال حساب، یک دورهٔ انتظار وجود دارد که در این مدت نخواهید توانست دوباره حسابتان را منتقل کنید
+      disabled_account: حساب فعلی شما پس از این کار دیگر قابل استفاده نخواهد بود. شما فقط خواهید توانست داده‌های خود را بیرون ببرید یا حساب را دوباره فعال کنید.
+      followers: این کار همهٔ پیگیران شما را از حساب فعلی به حساب تازه منتقل خواهد کرد
+      other_data: هیچ دادهٔ دیگری خودبه‌خود منتقل نخواهد شد
   moderation:
     title: مدیریت کاربران
   notification_mailer:
@@ -908,6 +982,7 @@ fa:
   settings:
     account: حساب
     account_settings: تنظیمات حساب
+    aliases: نام‌های مستعار
     appearance: نما
     authorized_apps: برنامه‌های مجاز
     back: بازگشت به ماستدون
@@ -968,6 +1043,8 @@ fa:
     pinned: نوشته‌های ثابت
     reblogged: بازبوقید
     sensitive_content: محتوای حساس
+  tags:
+    does_not_match_previous_name: با نام پیشین مطابق نیست
   terms:
     body_html: |
       <h2>سیاست رازداری</h2>
@@ -1085,7 +1162,9 @@ fa:
         disable: تا وقتی حساب شما متوقف باشد، داده‌های شما دست‌نخورده باقی می‌مانند، ولی تا وقتی که حسابتان باز نشده، نمی‌توانید هیچ کاری با آن بکنید.
         silence: تا وقتی حساب شما محدود باشد، تنها کسانی که از قبل پیگیر شما بودند نوشته‌های شما در این سرور را می‌بینند و شما در فهرست‌های عمومی دیده نمی‌شوید. ولی دیگران همچنان می‌توانند به دلخواه خودشان پیگیر شما شوند.
         suspend: حساب شما معلق شده است، و همهٔ نوشته‌ها و رسانه‌های تصویری شما به طور بازگشت‌ناپذیری پاک شده‌اند؛ چه از این سرور و چه از سرورهای دیگری که از آن‌ها پیگیر داشتید.
+      get_in_touch: با پاسخ به این ایمیل می‌توانید با دست‌اندرکاران %{instance} در تماس باشید.
       review_server_policies: مرور سیاست‌های این سرور
+      statuses: 'به طور خاص برای:'
       subject:
         disable: حساب %{acct} شما متوقف شده است
         none: هشدار برای %{acct}
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index 3d8fdce3a..2f8fd3497 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -10,9 +10,6 @@ fi:
     contact_missing: Ei asetettu
     contact_unavailable: Ei saatavilla
     documentation: Dokumentaatio
-    extended_description_html: |
-      <h3>Hyvä paikka säännöille</h3>
-      <p>Pidempää kuvausta ei ole vielä laadittu.</p>
     generic_description: "%{domain} on yksi verkostoon kuuluvista palvelimista"
     hosted_on: Mastodon palvelimella %{domain}
     learn_more: Lisätietoja
@@ -468,9 +465,6 @@ fi:
       too_many: Tiedostoja voi liittää enintään 4
   migrations:
     acct: uuden tilin käyttäjätunnus@verkkotunnus
-    currently_redirecting: 'Profiiliisi on asetettu uudelleenohjaus:'
-    proceed: Tallenna
-    updated_msg: Tilinsiirtoasetusten päivitys onnistui!
   moderation:
     title: Moderointi
   notification_mailer:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 15d6359b4..4b46e7a71 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -17,9 +17,6 @@ fr:
     contact_unavailable: Non disponible
     discover_users: Découvrez des utilisateur·rice·s
     documentation: Documentation
-    extended_description_html: |
-      <h3>Un bon endroit pour les règles</h3>
-      <p>La description étendue n’a pas été remplie.</p>
     federation_hint_html: Avec un compte sur %{instance}, vous pourrez suivre les gens sur n’importe quel serveur Mastodon et au-delà.
     generic_description: "%{domain} est seulement un serveur du réseau"
     get_apps: Essayez une application mobile
@@ -38,6 +35,13 @@ fr:
     status_count_before: Ayant publié
     tagline: Suivez vos ami·e·s et découvrez en de nouveaux·elles
     terms: Conditions d’utilisation
+    unavailable_content: Contenu non disponible
+    unavailable_content_description:
+      reason: 'Motif :'
+      rejecting_media: Les fichiers média de ce serveur ne seront pas traités et aucune miniature ne sera affichée, nécessitant un clic manuel vers l'autre serveur.
+      silenced: Les messages de ce serveur ne s'afficheront nulle part sauf votre flux personnel si vous suivez l'auteur.
+      suspended: Vous ne pourrez suivre personne de ce serveur, aucune donnée ne sera traitée ou stockée et aucune donnée ne sera échangée.
+    unavailable_content_html: Mastodon vous permet généralement de visualiser le contenu et d'interagir avec les utilisateurs de n'importe quel autre serveur dans le fédiverse. Voici les exceptions qui ont été faites sur ce serveur en particulier.
     user_count_after:
       one: utilisateur
       other: utilisateurs
@@ -225,10 +229,12 @@ fr:
       deleted_status: "(statut supprimé)"
       title: Journal d’audit
     custom_emojis:
+      assign_category: Attribuer une catégorie
       by_domain: Domaine
       copied_msg: Copie locale de l’émoji créée avec succès !
       copy: Copier
       copy_failed_msg: Impossible de faire une copie locale de cet émoji
+      create_new_category: Créer une nouvelle catégorie
       created_msg: Émoji créé avec succès !
       delete: Supprimer
       destroyed_msg: Émoji supprimé avec succès !
@@ -236,8 +242,10 @@ fr:
       disabled_msg: Émoji désactivé avec succès !
       emoji: Émoji
       enable: Activer
+      enabled: Activé
       enabled_msg: Émoji activé avec succès
       image_hint: PNG de moins de 50 Ko
+      list: Liste
       listed: Listé
       new:
         title: Ajouter un nouvel émoji personnalisé
@@ -245,6 +253,8 @@ fr:
       shortcode: Raccourci
       shortcode_hint: Au moins deux caractères, seulement des caractères alphanumériques ou des tirets bas
       title: Émojis personnalisés
+      uncategorized: Non catégorisé
+      unlist: Délisté
       unlisted: Délisté
       update_failed_msg: N’a pas pu mettre à jour cet émoji
       updated_msg: Émoji mis à jour avec succès !
@@ -376,6 +386,7 @@ fr:
       pending: En attente de l’approbation du relai
       save_and_enable: Sauvegarder et activer
       setup: Paramétrer une connexion de relais
+      signatures_not_enabled: Les relais ne fonctionneront pas correctement lorsque le mode sécurisé ou le mode liste blanche est activé
       status: Statut
       title: Relais
     report_notes:
@@ -424,6 +435,9 @@ fr:
       custom_css:
         desc_html: Modifier l’apparence avec une CSS chargée sur chaque page
         title: CSS personnalisé
+      default_noindex:
+        desc_html: Affecte tous les utilisateurs qui n'ont pas changé eux-mêmes ce paramètre
+        title: Opter pour le retrait de l'indexation des moteurs de recherche par défaut
       domain_blocks:
         all: À tout le monde
         disabled: À personne
@@ -515,6 +529,10 @@ fr:
       context: Contexte 
       directory: Dans le répertoire
       in_directory: "%{count} dans le répertoire"
+      last_active: Dernière activité
+      most_popular: Plus populaire
+      most_recent: Plus récent
+      name: Mot-clé
       review: État de traitement
       reviewed: Traité
       title: Hashtags
@@ -540,6 +558,12 @@ fr:
     new_trending_tag:
       body: 'Le hashtag #%{name} est populaire aujourd’hui, mais il n’a pas été approuvé. Il ne sera pas affiché publiquement à moins que l’autorisiez, ou sauvegardez simplement ce formulaire tel quel pour ne plus jamais en entendre parler.'
       subject: Nouveau hashtag en attente de traitement sur %{instance} (#%{name})
+  aliases:
+    add_new: Créer un alias
+    created_msg: Un nouvel alias a été créé avec succès. Vous pouvez maintenant lancer le déplacement depuis l'ancien compte.
+    deleted_msg: Suppression réussie de l'alias. Déplacer de ce compte vers celui-ci ne sera plus possible.
+    hint_html: Si vous voulez passer d'un autre compte à celui-ci, vous pouvez créer ici un alias, qui est nécessaire avant de pouvoir déplacer les abonné·e·s de l'ancien compte à celui-ci. Cette action en soi est <strong>inoffensive et réversible</strong>. <strong>La migration du compte est initiée à partir de l'ancien compte</strong>.
+    remove: Détacher l'alias
   appearance:
     advanced_web_interface: Interface web avancée
     advanced_web_interface_hint: 'Si vous voulez utiliser toute la largeur de votre écran, l’interface web avancée vous permet de configurer plusieurs colonnes différentes pour voir autant d’informations que vous le souhaitez en même temps : Accueil, notifications, fil public fédéré, un nombre illimité de listes et hashtags.'
@@ -599,6 +623,7 @@ fr:
       confirming: En attente de la confirmation par e-mail à compléter.
       functional: Votre compte est entièrement opérationnel.
       pending: Votre demande est en attente d'examen par notre personnel. Cela peut prendre un certain temps. Vous recevrez un courriel si votre demande est approuvée.
+      redirecting_to: Votre compte est inactif car il est actuellement redirigé vers %{acct}.
     trouble_logging_in: Vous avez un problème pour vous connecter ?
   authorize_follow:
     already_following: Vous suivez déjà ce compte
@@ -611,6 +636,11 @@ fr:
       return: Afficher le profil de l’utilisateur⋅ice
       web: Retour à l’interface web
     title: Suivre %{acct}
+  challenge:
+    confirm: Continuer
+    hint_html: "<strong>Astuce :</strong> Nous ne vous demanderons plus votre mot de passe pour la prochaine heure."
+    invalid_password: Mot de passe invalide
+    prompt: Confirmez votre mot de passe pour continuer
   datetime:
     distance_in_words:
       about_x_hours: "%{count} h"
@@ -626,10 +656,19 @@ fr:
       x_months: "%{count} mois"
       x_seconds: "%{count} s"
   deletes:
+    challenge_not_passed: Les renseignements que vous avez entrés n'étaient pas exacts
     confirm_password: Entrez votre mot de passe pour vérifier votre identité
+    confirm_username: Entrez votre nom d'utilisateur pour confirmer la procédure
     proceed: Supprimer compte
     success_msg: Votre compte a été supprimé avec succès
     warning:
+      before: 'Avant de procéder, veuillez lire attentivement ces notes :'
+      caches: Le contenu mis en cache par d'autres serveurs peut persister
+      data_removal: Vos messages et autres données seront définitivement supprimés
+      email_change_html: Vous pouvez <a href="%{path}">modifier votre adresse courriel</a> sans supprimer votre compte
+      email_contact_html: S'il n'arrive toujours pas, vous pouvez envoyer un courriel à <a href="mailto:%{email}">%{email}</a> pour de l'aide
+      email_reconfirmation_html: Si vous ne recevez pas le courriel de confirmation, vous pouvez le <a href="%{path}">demander à nouveau</a>
+      irreversible: Vous ne pourrez pas restaurer ou réactiver votre compte
       more_details_html: Pour plus de détails, voir la <a href="%{terms_path}">politique de confidentialité</a>.
       username_available: Votre nom d’utilisateur sera à nouveau disponible
       username_unavailable: Votre nom d’utilisateur restera indisponible
@@ -637,27 +676,10 @@ fr:
     directory: Annuaire des profils
     explanation: Découvrir des utilisateurs en se basant sur leurs centres d’intérêt
     explore_mastodon: Explorer %{title}
-  domain_blocks:
-    blocked_domains: Liste des domaines limités et bloqués
-    description: Ceci est la liste des serveurs envers qui %{instance} limite ou rejette la fédération.
-    domain: Domaine
-    media_block: Bloqueur de média
-    no_domain_blocks: "(Aucun bloqueur de domaine)"
-    severity: Sévérité
-    severity_legend:
-      media_block: Les fichiers de média provenant du serveur ne sont ni récupérés, ni stockés, ni affichés à l’utilisateur·rice.
-      silence: Les comptes des serveurs masqués peuvent être trouvés, suivis et interagis avec, mais leurs Toots n'apparaîtront pas dans les fil d'actualité publiques, et les notifications de ceux-ci ne parviendront pas aux utilisateurs locaux qui ne les suivent pas.
-      suspension: Aucun contenu des serveurs suspendus n'est stocké ou affiché, ni ne leur est communiqué. Les interactions des serveurs suspendus sont ignorées.
-      suspension_disclaimer: Les serveurs suspendus peuvent parfois récupérer du contenu public de ce serveur.
-      title: Séverités
-    show_rationale: Voir le raisonnement
-    silence: Masquer
-    suspension: Suspendre
-    title: "%{instance} Liste des instances bloquées"
   domain_validator:
     invalid_domain: n’est pas un nom de domaine valide
   errors:
-    '400': The request you submitted was invalid or malformed.
+    '400': La demande que vous avez soumise est invalide ou mal formée.
     '403': Vous n’avez pas accès à cette page.
     '404': La page que vous recherchez n’existe pas.
     '406': Cette page n'est pas disponible au format demandé.
@@ -669,7 +691,7 @@ fr:
     '500':
       content: Nous sommes désolé·e·s, mais quelque chose s’est mal passé de notre côté.
       title: Cette page n’est pas correcte
-    '503': The page could not be served due to a temporary server failure.
+    '503': La page n'a pas pu être servie en raison d'une défaillance temporaire du serveur.
     noscript_html: Pour utiliser Mastodon, veuillez activer JavaScript. Sinon, essayez l’une des <a href="%{apps_path}">applications natives</a> pour Mastodon pour votre plate-forme.
   existing_username_validator:
     not_found: n’a pas trouvé d’utilisateur·rice local·e avec ce nom
@@ -719,6 +741,7 @@ fr:
     all: Tous
     changes_saved_msg: Les modifications ont été enregistrées avec succès !
     copy: Copier
+    no_batch_actions_available: Aucune action par lots disponible sur cette page
     order_by: Classer par
     save_changes: Enregistrer les modifications
     validation_errors:
@@ -790,9 +813,31 @@ fr:
       too_many: Impossible de joindre plus de 4 fichiers
   migrations:
     acct: profil@domaine du nouveau compte
-    currently_redirecting: 'Votre profil va être redirigé vers :'
-    proceed: Enregistrer
-    updated_msg: Les paramètres de votre migration de compte ont été mis à jour avec succès !
+    cancel: Annuler la redirection
+    cancel_explanation: Annuler la redirection réactivera votre compte courant, mais ne rapportera pas les abonnés qui ont été déplacés sur ce compte.
+    cancelled_msg: Suppression de la redirection réussie.
+    errors:
+      already_moved: est le même compte que vous avez déjà déplacé vers
+      missing_also_known_as: ne référence pas rétroactivement ce compte
+      move_to_self: ne peut pas être un compte courant
+      not_found: n'a pas été trouvé
+      on_cooldown: Vous êtes en refroidissement
+    followers_count: Abonnés au moment du déplacement
+    incoming_migrations: Déplacement d'un compte différent
+    incoming_migrations_html: Pour passer d'un autre compte à celui-ci, vous devez d'abord <a href="%{path}">créer un alias de compte</a>.
+    moved_msg: Votre compte est maintenant redirigé vers %{acct} et vos abonnés sont déplacés.
+    not_redirecting: Votre compte n'est pas redirigé vers un autre compte actuellement.
+    on_cooldown: Vous avez récemment migré votre compte. Cette fonction sera à nouveau disponible dans %{count} jours.
+    past_migrations: Migrations passées
+    proceed_with_move: Déplacer les abonnés
+    redirecting_to: Votre compte est redirigé vers %{acct}.
+    warning:
+      backreference_required: Le nouveau compte doit d'abord être configuré pour faire référence à celui-ci
+      before: 'Avant de procéder, veuillez lire attentivement ces notes :'
+      cooldown: Après le déménagement, il y a une période de refroidissement pendant laquelle vous ne pourrez plus bouger
+      disabled_account: Votre compte actuel ne sera pas entièrement utilisable par la suite. Cependant, vous aurez accès à l'exportation de données et à la ré-activation.
+      followers: Cette action va déplacer tous les abonnés du compte courant vers le nouveau compte
+      other_data: Aucune autre donnée ne sera déplacée automatiquement
   moderation:
     title: Modération
   notification_mailer:
@@ -937,6 +982,7 @@ fr:
   settings:
     account: Compte
     account_settings: Paramètres du compte
+    aliases: Alias du compte
     appearance: Apparence
     authorized_apps: Applications autorisées
     back: Retour vers Mastodon
diff --git a/config/locales/gl.yml b/config/locales/gl.yml
index 20f535ad5..3924eeedc 100644
--- a/config/locales/gl.yml
+++ b/config/locales/gl.yml
@@ -17,9 +17,6 @@ gl:
     contact_unavailable: N/A
     discover_users: Descubra usuarias
     documentation: Documentación
-    extended_description_html: |
-      <h3>Un bo lugar para regras</h3>
-      <p>A descrición extendida aínda non se proporcionou.</p>
     federation_hint_html: Con unha conta en %{instance} poderá seguir a outras persoas en calquera dos servidores Mastodon e incluso máis.
     generic_description: "%{domain} é un servidor na rede"
     get_apps: Probe cunha app móbil
@@ -38,6 +35,13 @@ gl:
     status_count_before: Que publicaron
     tagline: Siga as amizades e faga outras novas
     terms: Termos do servizo
+    unavailable_content: Contido non dispoñible
+    unavailable_content_description:
+      reason: 'Razón:'
+      rejecting_media: Os ficheiros de medios de este servidor non se procesarán e non se mostrarán miniaturas, precisando solicitarse manualmente ao outro servidor.
+      silenced: As publicacións desde este servidor non se mostrarán en ningún lugar excepto no Inicio se segues ao autor.
+      suspended: Non poderás seguir a ninguén desde este servidor, e non se procesarán nin se gardarán datos que procedan del, e non se intercambiarán datos.
+    unavailable_content_html: Normalmente Mastodon permíteche ver contidos de outros servidores do fediverso e interactuar coas súas usuarias. Estas son as excepcións que se estableceron en este servidor particular.
     user_count_after:
       one: usuaria
       other: usuarias
@@ -427,6 +431,9 @@ gl:
       custom_css:
         desc_html: Modificar o aspecto con CSS cargado en cada páxina
         title: CSS persoalizado
+      default_noindex:
+        desc_html: Aféctalle a todas as usuarias que non cambiaron os axustes elas mesmas
+        title: Por omisión exclúe as usuarias do indexado por servidores de busca
       domain_blocks:
         all: Para todas
         disabled: Para ninguén
@@ -518,6 +525,10 @@ gl:
       context: Contexto
       directory: No directorio
       in_directory: "%{count} no directorio"
+      last_active: Úlimo activo
+      most_popular: Máis popular
+      most_recent: Máis recente
+      name: Etiqueta
       review: Estado de revisión
       reviewed: Revisado
       title: Etiquetas
@@ -543,6 +554,12 @@ gl:
     new_trending_tag:
       body: 'A etiqueta #%{name} é tendencia hoxe, pero non foi previamente revisada. Non se mostrará publicamente a menos que vostede o permita, ou garde o formulario para facer que non se lle consulte de novo.'
       subject: Unha nova etiqueta que revisar en %{instance} (#%{name})
+  aliases:
+    add_new: Crear alcume
+    created_msg: Creou un novo alcume correctamente. Pode iniciar o movemento desde a conta antiga.
+    deleted_msg: Eliminou correctamente o alias. Xa non será posible mover desde esa conta a esta.
+    hint_html: Se quere mudarse desde outra conta a esta nova, aquí pode crear un alcume, que é requerido antes de poder proceder a mover os seguidores da conta antiga a esta nova. Esta acción por si mesma é <strong>inocua e reversible</strong>. <strong>A migración da conta iníciase desde a conta antiga</strong>.
+    remove: Desligar alcume
   appearance:
     advanced_web_interface: Interface web avanzada
     advanced_web_interface_hint: Se quere utilizar todo o ancho da súa pantalla, a interface web avanzada permítelle configurar diferentes columnas para ver tanta información como desexe. Inicio, notificacións, liña temporal federada, calquera número de listas e etiquetas.
@@ -602,6 +619,7 @@ gl:
       confirming: Agardando a confirmación do correo enviado.
       functional: A súa conta está totalmente operativa.
       pending: A súa aplicación está pendente de revisión. Poderíanos levar algún tempo. Recibirá un correo se a aplicación está aprobada.
+      redirecting_to: A túa conta está inactiva porque está redirixida a %{acct}.
     trouble_logging_in: Problemas para conectar?
   authorize_follow:
     already_following: Xa está a seguir esta conta
@@ -614,6 +632,11 @@ gl:
       return: Mostrar o perfil da usuaria
       web: Ir a web
     title: Seguir %{acct}
+  challenge:
+    confirm: Continuar
+    hint_html: "<strong>Nota:</strong> Non che pediremos o contrasinal na seguinte hora."
+    invalid_password: Contrasinal incorrecto
+    prompt: Confirma o contrasinal para continuar
   datetime:
     distance_in_words:
       about_x_hours: "%{count}h"
@@ -629,7 +652,9 @@ gl:
       x_months: "%{count}mes"
       x_seconds: "%{count}s"
   deletes:
+    challenge_not_passed: A información introducida non é correcta
     confirm_password: Introduza o seu contrasinal para verificar a súa identidade
+    confirm_username: Introduce o nome de usuaria para confirmar o procedemento
     proceed: Eliminar conta
     success_msg: A súa conta eliminouse correctamente
     warning:
@@ -647,23 +672,6 @@ gl:
     directory: Directorio de perfil
     explanation: Descubra usuarias según o seu interese
     explore_mastodon: Explorar %{title}
-  domain_blocks:
-    blocked_domains: Lista de dominios limitados e bloqueados
-    description: Esta é a lista dos servidores cos que %{instance} limita ou rexeita federar.
-    domain: Dominio
-    media_block: Bloqueo de medios
-    no_domain_blocks: "(Sen bloqueo de medios)"
-    severity: Rigurosidade
-    severity_legend:
-      media_block: Os ficheiros de medios procedentes do servidor non se obterán, gardarán nin mostrarán as usuarias.
-      silence: As contas de servidores silenciados pódense atopar, seguir e interactuar con elas, pero os seus toots non aparecerán na liña temporal púbica, as notificacións procedentes deles non chegarán as usuarias que non as están a seguir.
-      suspension: Non se mostra nin garda ningún contido de servidores suspendidos, tampouco se lles envía contido. As interaccións con servidores suspendidos son ignoradas.
-      suspension_disclaimer: Os servidores suspendidos poderían obter ocasionalmente contido público de este servidor.
-      title: Rigurosidades
-    show_rationale: Mostrar razón
-    silence: Silenciar
-    suspension: Suspensión
-    title: "%{instance} Lista de instancias bloqueadas"
   domain_validator:
     invalid_domain: non é un nome de dominio válido
   errors:
@@ -801,9 +809,31 @@ gl:
       too_many: Non pode anexar máis de 4 ficheiros
   migrations:
     acct: nomeusuaria@dominio da nova conta
-    currently_redirecting: 'O seu perfil está listo para redirixir a:'
-    proceed: Gardar
-    updated_msg: O axuste de migración da conta actualizouse correctamente!
+    cancel: Cancelar a redirección
+    cancel_explanation: Ao cancelar a redirección reactivarás a conta actual, pero non poderás traer de volta os seguidores que se moveron a esa conta.
+    cancelled_msg: Cancelouse a redirección.
+    errors:
+      already_moved: é a mesma conta a que xa te moveches
+      missing_also_known_as: non está referenciando hacia esta conta
+      move_to_self: non pode ser a conta actual
+      not_found: non se atopou
+      on_cooldown: Estas no período de calma
+    followers_count: Seguidoras no momento da migración
+    incoming_migrations: Movendo desde unha conta diferente
+    incoming_migrations_html: Para migrar doutra conta cara esta, primeiro debes <a href="%{path}">crear un alias da conta</a>.
+    moved_msg: A túa conta está redirixindo agora a %{acct} e os teus seguidores movéronse alí.
+    not_redirecting: Neste momento a túa conta non está redirixindo cara a ningunha outra.
+    on_cooldown: Migraches recentemente a conta. Esta función estará dispoñible de novo en %{count} días.
+    past_migrations: Migracións pasadas
+    proceed_with_move: Mover seguidoras
+    redirecting_to: A conta está redirixindo cara a %{acct}.
+    warning:
+      backreference_required: Tes que configurar primeiro a nova conta para referenciar hacia esta
+      before: 'Antes de seguir, por favor lé estas notas con atención:'
+      cooldown: Tras a migración existe un período de calma durante o cal non poderás voltar a migrar de novo
+      disabled_account: Tras o cambio a túa conta actual non será totalmente usable, pero terás acceso a exportar os datos e tamén a reactivación.
+      followers: Esta acción moverá todas as túas seguidoras desde a conta actual a nova conta
+      other_data: Non se moverán outros datos de xeito automático
   moderation:
     title: Moderación
   notification_mailer:
@@ -948,6 +978,7 @@ gl:
   settings:
     account: Conta
     account_settings: Axustes da conta
+    aliases: Alcumes da conta
     appearance: Aparencia
     authorized_apps: Apps autorizadas
     back: Voltar a Mastodon
diff --git a/config/locales/he.yml b/config/locales/he.yml
index 62c04a8e8..f7b121777 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -9,9 +9,6 @@ he:
     contact_missing: ללא הגדרה
     contact_unavailable: לא רלוונטי/חסר
     documentation: תיעוד
-    extended_description_html: |
-      <h3>מקום טוב לכללים</h3>
-      <p>התיאור המורחב טרם הוגדר.</p>
     generic_description: "%{domain} הוא שרת אחד בתוך הרשת"
     hosted_on: מסטודון שיושב בכתובת %{domain}
     learn_more: מידע נוסף
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 5d9097d09..c1222018d 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -17,9 +17,6 @@ hu:
     contact_unavailable: N/A
     discover_users: Találj meg másokat
     documentation: Dokumentáció
-    extended_description_html: |
-      <h3>Ez itt a szabályzat helye</h3>
-      <p>Még nem állítottál be bővebb leírást.</p>
     federation_hint_html: Egy %{instance} fiókkal bármely más Mastodon szerveren vagy a föderációban lévő felhasználót követni tudsz.
     generic_description: "%{domain} csak egy a számtalan szerver közül a föderációban"
     get_apps: Próbálj ki egy mobil appot
@@ -38,6 +35,13 @@ hu:
     status_count_before: eddig
     tagline: Kövess barátokat és találj újakat
     terms: Felhasználási feltételek
+    unavailable_content: A tartalom nem elérhető
+    unavailable_content_description:
+      reason: 'Indok:'
+      rejecting_media: A szerverről származó médiafájlok nem kerülnek feldolgozásra, és nem jelennek meg miniatűrök, amelyek kézi átkattintást igényelnek a másik szerverre.
+      silenced: A szerver hozzászólásai csak a saját hírvonalon jelennek meg, ha követik a szerzőt.
+      suspended: Nem fogsz tudni követni senkit ebből a szerverből, és nem kerül feldolgozásra vagy tárolásra a tőle származó adat, és nincs adatcsere.
+    unavailable_content_html: A Mastodon általában mindenféle tartalomcserét és interakciót lehetővé tesz bármelyik szerverrel a fediverzumban. Ezek azok a kivételek, melyek a mi szerverünkön érvényben vannak.
     user_count_after:
       one: felhasználónk
       other: felhasználónk
@@ -45,6 +49,8 @@ hu:
     what_is_mastodon: Mi a Mastodon?
   accounts:
     choices_html: "%{name} választásai:"
+    endorsements_hint: A webes felületen jóváhagyhatod a követett embereket, és itt jelennek meg.
+    featured_tags_hint: Szerepeltethetsz bizonyos hashtageket, melyek itt jelennek majd meg.
     follow: Követés
     followers:
       one: Követő
@@ -56,6 +62,7 @@ hu:
     media: Média
     moved_html: "%{name} ide költözött: %{new_profile_link}"
     network_hidden: Ez az információ nem elérhető
+    never_active: Soha
     nothing_here: Nincs itt semmi!
     people_followed_by: "%{name} követettjei"
     people_who_follow: "%{name} követői"
@@ -222,10 +229,12 @@ hu:
       deleted_status: "(törölt tülk)"
       title: Audit napló
     custom_emojis:
+      assign_category: Kategóriák
       by_domain: Domain
       copied_msg: Sikeresen létrehoztuk az emoji helyi másolatát
       copy: Másolás
       copy_failed_msg: Emoji helyi másolatának létrehozása sikertelen
+      create_new_category: Új kategória létrehozása
       created_msg: Emoji létrehozva!
       delete: Törlés
       destroyed_msg: Emoji törlése sikeres!
@@ -242,6 +251,7 @@ hu:
       shortcode: Rövidítés
       shortcode_hint: Legalább két karakter, csak betűk, számok és alsóvonás
       title: Egyedi emojik
+      uncategorized: Nem kategorizált
       unlisted: Nincs listázva
       update_failed_msg: Nem sikerült frissíteni az emojit
       updated_msg: Emoji sikeresen frissítve!
@@ -421,6 +431,16 @@ hu:
       custom_css:
         desc_html: Változtasd meg a kinézetet ebben a CSS-ben, mely minden oldalon be fog töltődni
         title: Egyedi CSS
+      default_noindex:
+        desc_html: Olyan felhasználókat érinti, akik nem módosították ezt a beállítást
+        title: Alapértelmezésként ne indexeljék a keresők a felhasználóinkat
+      domain_blocks:
+        all: Mindenkinek
+        disabled: Senkinek
+        title: Domain tiltások megjelenitése
+        users: Bejelentkezett helyi felhasználóknak
+      domain_blocks_rationale:
+        title: Mutasd meg az indokolást
       hero:
         desc_html: A kezdőoldalon látszik. Legalább 600x100px méret javasolt. Ha nincs beállítva, a szerver bélyegképet használjuk
         title: Hősi kép
@@ -490,6 +510,7 @@ hu:
         delete: Törlés
         nsfw_off: Szenzitív megjelölés törlése
         nsfw_on: Megjelölés szenzitív tartalomként
+      deleted: Törölve
       failed_to_execute: Végrehajtás sikertelen
       media:
         title: Média
@@ -504,6 +525,10 @@ hu:
       context: Környezet
       directory: Katalógusban
       in_directory: "%{count} a katalógusban"
+      last_active: Utoljára aktív
+      most_popular: Legnépszerűbb
+      most_recent: Legutóbbi
+      name: Címke
       review: Engedélyezés állapota
       reviewed: Engedélyezett
       title: Hashtagek
@@ -529,6 +554,12 @@ hu:
     new_trending_tag:
       body: 'A #%{name} hashtag trendi a mai napon, de még nem engedélyeztük eddig. Nem mutatjuk meg nyilvánosan, hacsak nem engedélyezed. Csak simán mentsd az űrlapot, ha soha többé nem akarsz erről a hashtagről hallani.'
       subject: Új hashtag (#%{name}) engedélyezésre vár a %{instance} szerveren
+  aliases:
+    add_new: Alias készítése
+    created_msg: Elkészült az új aliasod. Most már elkezdheted a költöztetést a régi fiókból.
+    deleted_msg: Sikeresen eltávolítottad az aliast. A fiókról erre a fiókra való áttérés már nem lehetséges.
+    hint_html: Ha másik fiókról kívánsz átlépni erre a fiókra, itt létrehozhatsz egy aliast, amelyre szükség van, mielőtt folytathatod a követők áthelyezését a régi fiókból erre. Ez az áthelyezés önmagában <strong>ártalmatlan és visszafordítható</strong> folyamat. <strong>A fiók áttelepítését a régi fiókból indul el. </strong>
+    remove: Alias szétkapcsolása
   appearance:
     advanced_web_interface: Haladó webes felület
     advanced_web_interface_hint: 'Ha szeretnéd, a teljes képernyőszélességet felhasználhatod. A haladó webes felülettel különböző oszlopokat állíthatsz be, hogy egyszerre annyi infót láthass, amennyit csak akarsz: Saját idővonal, értesítések, föderációs idővonal, bármennyi lista vagy hashtag.'
@@ -558,6 +589,10 @@ hu:
     checkbox_agreement_without_rules_html: Egyetértek a <a href="%{terms_path}" target="_blank">felhasználási feltételekkel</a>
     delete_account: Felhasználói fiók törlése
     delete_account_html: Felhasználói fiókod törléséhez <a href="%{path}">kattints ide</a>. A rendszer újbóli megerősítést fog kérni.
+    description:
+      prefix_invited_by_user: "@%{name} meghív téged, hogy csatlakozz erre a Mastodon szerverre!"
+      prefix_sign_up: Regisztrláj még ma a Mastodonra!
+      suffix: Egy fiókkal követhetsz másokat, tülkölhetsz, eszmét cserélhetsz más Mastodon szerverek felhasználóival!
     didnt_get_confirmation: Nem kaptad meg a megerősítési lépéseket?
     forgot_password: Elfelejtetted a jelszavad?
     invalid_reset_password_token: A jelszó-visszaállítási kulcs nem megfelelő vagy lejárt. Kérlek generálj egy újat.
@@ -584,6 +619,7 @@ hu:
       confirming: Várakozás a visszaigazolásra.
       functional: A fiókod teljesen működőképes.
       pending: A jelentkezésed engedélyezésre vár. Ez eltarthat egy ideig. Kapsz egy e-mailt, ha az elbírálás megtörtént.
+      redirecting_to: A fiókod inaktív, mert jelenleg ide %{acct} van átirányítva.
     trouble_logging_in: Problémád van a bejelentkezéssel?
   authorize_follow:
     already_following: Már követed ezt a felhasználót
@@ -596,6 +632,11 @@ hu:
       return: Visszatérés a felhasználó profiloldalára
       web: Megtekintés a weben
     title: "%{acct} követése"
+  challenge:
+    confirm: Folytatás
+    hint_html: "<strong>Hasznos:</strong> Nem fogjuk megint a jelszavadat kérdezni a következő órában."
+    invalid_password: Érvénytelen jelszó
+    prompt: Add meg a jelszót a folytatáshoz
   datetime:
     distance_in_words:
       about_x_hours: "%{count}ó"
@@ -611,9 +652,22 @@ hu:
       x_months: "%{count}h"
       x_seconds: "%{count}mp"
   deletes:
+    challenge_not_passed: A beírt információ helytelen
     confirm_password: Személyazonosságod megerősítéséhez írd be a jelenlegi jelszavad
+    confirm_username: Add meg a felhasználói nevedet a jóváhagyáshoz
     proceed: Felhasználói fiók törlése
     success_msg: Felhasználói fiókod sikeresen töröltük
+    warning:
+      before: 'Mielőtt továbbmész, kérlek olvasd el ezt alaposan:'
+      caches: Más szerverek által cache-elt tartalmak még megmaradhatnak
+      data_removal: A tülkjeid és minden más adatod véglegesen törlődni fog
+      email_change_html: <a href="%{path}">Megváltoztathatod az email címed</a> a fiókod törlése nélkül
+      email_contact_html: Ha még mindig nem érkezik meg, emailezhetsz ide <a href="mailto:%{email}">%{email}</a> segítségért
+      email_reconfirmation_html: Ha nem kaptad meg a megerősítő emailt, <a href="%{path}">itt újrakérheted</a>
+      irreversible: Nem fogod tudni visszaállítani vagy újraaktiválni a fiókodat
+      more_details_html: A részletekért nézd meg az <a href="%{terms_path}">adatvédelmi szabályzatot</a>.
+      username_available: A fiókod ismét elérhetővé válik
+      username_unavailable: A fiókod elérhetetlen marad
   directories:
     directory: Profilok
     explanation: Találj másokra érdeklődésük alapján
@@ -621,10 +675,10 @@ hu:
   domain_validator:
     invalid_domain: nem egy valódi domain név
   errors:
-    '400': The request you submitted was invalid or malformed.
+    '400': A küldött kérés érvénytelen vagy hibás volt.
     '403': Nincs jogosultságod az oldal megtekintéséhez.
     '404': Az általad keresett oldal nem található.
-    '406': This page is not available in the requested format.
+    '406': Ez az oldal a kért formátumban nem áll rendelkezésre.
     '410': Az általad keresett oldal már nem létezik.
     '422':
       content: Megerősítés sikertelen. Nem tiltottad le esetleg a sütiket?
@@ -633,7 +687,7 @@ hu:
     '500':
       content: Sajnáljuk, valami hiba történt a mi oldalunkon.
       title: Az oldal nem megfelelő
-    '503': The page could not be served due to a temporary server failure.
+    '503': Az oldalt nem tudjuk megmutatni átmeneti szerverprobléma miatt.
     noscript_html: A Mastodon webalkalmazás használatához engedélyezned kell a JavaScriptet. A másik megoldás, hogy kipróbálsz egy platformodnak megfelelő <a href="%{apps_path}">alkalmazást</a>.
   existing_username_validator:
     not_found: ezzel a névvel nem találtunk helyi felhasználót
@@ -657,6 +711,7 @@ hu:
     add_new: Új hozzáadása
     errors:
       limit: Már kiemelted a maximálisan engedélyezett számú hashtaget
+    hint_html: "<strong>Mik a kiemelt hashtagek?</strong> Ezek állandóan megjelennek a nyilvános profilodon és lehetővé teszik, hogy mások kifejezetten az ezekhez tartozó tülkjeidet böngésszék. Jó eszköz ez kreatív munkák vagy hosszútávú projektek nyomonkövetésére."
   filters:
     contexts:
       home: Saját idővonal
@@ -677,10 +732,12 @@ hu:
     developers: Fejlesztőknek
     more: Többet…
     resources: Segédanyagok
+    trending_now: Most trendi
   generic:
     all: Mind
     changes_saved_msg: A változásokat elmentettük!
     copy: Másolás
+    no_batch_actions_available: Ezen az oldalon nem elérhetőek kötegelt műveletek
     order_by: Rendezés
     save_changes: Változások mentése
     validation_errors:
@@ -752,9 +809,31 @@ hu:
       too_many: Maximum négy fájlt csatolhatsz a tülkhöz
   migrations:
     acct: Az új fiók felhasznalonev@domain formátumban
-    currently_redirecting: 'A profilod az alábbi fiókra van átirányítva:'
-    proceed: Mentés
-    updated_msg: Fiókod átirányítási beállításait sikeresen mentettük!
+    cancel: Átirányítás törlése
+    cancel_explanation: Az átirányítás törlése reaktiválja a fiókodat, de nem fogja visszahozni azokat a követőidet, akik közben a másik fiókhoz kerültek át.
+    cancelled_msg: Az átirányítást sikeresen töröltük.
+    errors:
+      already_moved: ugyanaz a fiók, ahová már elköltöztél
+      missing_also_known_as: nem hivatkozza vissza ezt a fiókot
+      move_to_self: nem lehet az aktuális fiók
+      not_found: nem található
+      on_cooldown: Még tart a türelmi idő
+    followers_count: Követő a költözéskor
+    incoming_migrations: Más fiókból költöző
+    incoming_migrations_html: Ahhoz, hogy egy másik fiókból ebbe költözz, először <a href="%{path}">hozz létre egy fiók aliast</a>.
+    moved_msg: A fiókod mostantól ide %{acct} irányít át, a követőidet átköltöztetjük.
+    not_redirecting: A fiókod nincs átirányítva jelenleg sehová sem.
+    on_cooldown: Nemrég költöztetted a fiókod. Ez a funkció %{count} nap múlva lesz megint elérhető.
+    past_migrations: Eddigi költözések
+    proceed_with_move: Követők átköltöztetése
+    redirecting_to: A fiókod át van irányítva ide %{acct}.
+    warning:
+      backreference_required: Az új fiókot először be kell úgy állítani, hogy ezt visszahivatkozza
+      before: 'Mielőtt továbbmész, olvasd el ezeket kérlek figyelmesen:'
+      cooldown: A költözés után van egy türelmi idő, mely alatt nem tudsz majd újra költözni
+      disabled_account: A jelenlegi fiókod nem lesz teljesen használható ezután. Viszont elérhető lesz majd az adatexport funkció, valamint a reaktiválás is.
+      followers: Ez a művelet az összes követődet a jelenlegi fiókról az újra fogja költöztetni
+      other_data: Más adatot nem fogunk automatikusan mozgatni
   moderation:
     title: Moderáció
   notification_mailer:
@@ -899,6 +978,7 @@ hu:
   settings:
     account: Fiók
     account_settings: Fiók beállítások
+    aliases: Fiók aliasok
     appearance: Megjelenés
     authorized_apps: Jóváhagyott alkalmazások
     back: Vissza a Mastodonhoz
@@ -1078,7 +1158,9 @@ hu:
         disable: A fiókod befagyasztott állapotban megtartja minden adatát, de feloldásig nem csinálhatsz vele semmit.
         silence: A fiókod korlátozott állapotában csak a követőid láthatják a tülkjeidet, valamint nem kerülsz rá nyilvános idővonalakra. Ugyanakkor mások manuálisan még követhetnek.
         suspend: A fiókodat felfüggesztették, így minden tülköd és feltöltött fájlod menthetetlenül elveszett erről a szerverről és minden olyanról is, ahol voltak követőid.
+      get_in_touch: Válaszolhatsz erre az emailre, hogy kapcsolatba lépj a %{instance} csapatával.
       review_server_policies: Szerver szabályzat átnézése
+      statuses: 'Különösen hozzá:'
       subject:
         disable: A fiókodat %{acct} befagyasztották
         none: Figyelmeztetés a %{acct} fióknak
diff --git a/config/locales/id.yml b/config/locales/id.yml
index 81a8ffd1f..bd47d05f8 100644
--- a/config/locales/id.yml
+++ b/config/locales/id.yml
@@ -10,9 +10,6 @@ id:
     contact_missing: Belum diset
     contact_unavailable: Tidak Tersedia
     documentation: Dokumentasi
-    extended_description_html: |
-      <h3>Tempat yang baik untuk peraturan</h3>
-      <p>Deskripsi lainnya belum diset.</p>
     generic_description: "%{domain} adalah satu server dalam jaringan"
     hosted_on: Mastodon dihosting di %{domain}
     learn_more: Pelajari selengkapnya
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 7b3eede09..447ac4a1e 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -17,9 +17,6 @@ it:
     contact_unavailable: N/D
     discover_users: Scopri utenti
     documentation: Documentazione
-    extended_description_html: |
-      <h3>Un buon posto per le regole</h3>
-      <p>La descrizione estesa non è ancora stata preparata.</p>
     federation_hint_html: Con un account su %{instance} sarai in grado di seguire persone su qualsiasi server Mastodon e oltre.
     generic_description: "%{domain} è un server nella rete"
     get_apps: Prova un'app per smartphone
@@ -38,6 +35,10 @@ it:
     status_count_before: Che hanno pubblicato
     tagline: Segui amici e trovane di nuovi
     terms: Termini di Servizio
+    unavailable_content: Contenuto non disponibile
+    unavailable_content_description:
+      reason: 'Motivo:'
+      rejecting_media: I file multimediali di questo server non saranno elaborati e non verranno visualizzate miniature, che richiedono clic manuale sull'altro server.
     user_count_after:
       one: utente
       other: utenti
@@ -57,6 +58,7 @@ it:
     media: Media
     moved_html: "%{name} si è spostato su %{new_profile_link}:"
     network_hidden: Questa informazione non e' disponibile
+    never_active: Mai
     nothing_here: Qui non c'è nulla!
     people_followed_by: Persone seguite da %{name}
     people_who_follow: Persone che seguono %{name}
@@ -223,10 +225,12 @@ it:
       deleted_status: "(stato cancellato)"
       title: Registro di controllo
     custom_emojis:
+      assign_category: Assegna categoria
       by_domain: Dominio
       copied_msg: Creata con successo una copia locale dell'emoji
       copy: Copia
       copy_failed_msg: Impossibile creare una copia locale di questo emoji
+      create_new_category: Crea nuova categoria
       created_msg: Emoji creato con successo!
       delete: Elimina
       destroyed_msg: Emoji distrutto con successo!
@@ -234,6 +238,7 @@ it:
       disabled_msg: Questa emoji è stata disabilitata con successo
       emoji: Emoji
       enable: Abilita
+      enabled: Abilitato
       enabled_msg: Questa emoji è stata abilitata con successo
       image_hint: PNG fino a 50 KB
       listed: Elencato
@@ -243,11 +248,13 @@ it:
       shortcode: Scorciatoia
       shortcode_hint: Almeno due caratteri, solo caratteri alfanumerici e trattino basso
       title: Emoji personalizzate
+      uncategorized: Nessuna categoria
       unlisted: Non elencato
       update_failed_msg: Impossibile aggiornare questa emojii
       updated_msg: Emoji aggiornata con successo!
       upload: Carica
     dashboard:
+      authorized_fetch_mode: Modalità sicura
       backlog: lavori arretrati
       config: Configurazione
       feature_deletions: Cancellazioni di account
@@ -512,6 +519,10 @@ it:
       context: Contesto
       directory: Nella directory
       in_directory: "%{count} nella directory"
+      last_active: Ultima attività
+      most_popular: Più popolari
+      most_recent: Più recenti
+      name: Hashtag
       reviewed: Controllato
       title: Hashtag
       trending_right_now: Di tendenza ora
@@ -535,6 +546,8 @@ it:
     new_trending_tag:
       body: 'L''hashtag #%{name} oggi è di tendenza, ma non è stato mai controllato. Non sarà visualizzato pubblicamente se non lo permetti; se salvi il form senza modifiche non lo vedrai mai più.'
       subject: Nuovo hashtag pronto per essere controllato su %{instance} (%{name})
+  aliases:
+    add_new: Crea alias
   appearance:
     advanced_web_interface: Interfaccia web avanzata
     advanced_web_interface_hint: |-
@@ -602,6 +615,11 @@ it:
       return: Mostra il profilo dell'utente
       web: Vai al web
     title: Segui %{acct}
+  challenge:
+    confirm: Continua
+    hint_html: "<strong>Suggerimento:</strong> Non ti chiederemo di nuovo la tua password per la prossima ora."
+    invalid_password: Password non valida
+    prompt: Conferma la tua password per continuare
   datetime:
     distance_in_words:
       about_x_hours: "%{count} ore"
@@ -617,30 +635,17 @@ it:
       x_months: "%{count} mesi"
       x_seconds: "%{count} secondi"
   deletes:
+    challenge_not_passed: Le informazioni che hai inserito non sono corrette
     confirm_password: Inserisci la tua password attuale per verificare la tua identità
+    confirm_username: Inserisci il tuo nome utente per confermare la procedura
     proceed: Cancella l'account
     success_msg: Il tuo account è stato cancellato
+    warning:
+      before: 'Prima di procedere, per favore leggi attentamente queste note:'
   directories:
     directory: Directory dei profili
     explanation: Scopri utenti in base ai loro interessi
     explore_mastodon: Esplora %{title}
-  domain_blocks:
-    blocked_domains: Elenco dei domini limitati e bloccati
-    description: Questo è l'elenco dei server con cui %{instance} limita o rifiuta la federazione.
-    domain: Dominio
-    media_block: Blocco dei media
-    no_domain_blocks: "(Nessun blocco di dominio)"
-    severity: Gravità
-    severity_legend:
-      media_block: I file multimediali provenienti dal server non sono recuperati, memorizzati o visualizzati all'utente.
-      silence: Gli account di server silenziati possono essere trovati e seguiti, e gli utenti possono interagire con essi, ma i loro toot non appariranno nelle timeline pubbliche e le relative notifiche non raggiungeranno gli utenti locali che non li seguono.
-      suspension: Nessun contenuto dai server sospesi è memorizzato o visualizzato, e nessun contenuto gli viene inviato. Le interazioni dai server sospesi sono ignorate.
-      suspension_disclaimer: I server sospesi possono talvolta recuperare contenuti pubblici da questo server.
-      title: Gravità
-    show_rationale: Mostra motivazione
-    silence: Silenzia
-    suspension: Sospensione
-    title: "%{instance} Elenco delle istanze bloccate"
   domain_validator:
     invalid_domain: non è un nome di dominio valido
   errors:
@@ -777,9 +782,6 @@ it:
       too_many: Impossibile allegare più di 4 file
   migrations:
     acct: utente@dominio del nuovo account
-    currently_redirecting: 'Il tuo profilo sarà ridirezionato a:'
-    proceed: Salva
-    updated_msg: L'impostazione per la migrazione dell'account è sta aggiornata!
   moderation:
     title: Moderazione
   notification_mailer:
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index f39e048ca..3ad4cf3e9 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -17,9 +17,6 @@ ja:
     contact_unavailable: N/A
     discover_users: ユーザーを見つける
     documentation: ドキュメント
-    extended_description_html: |
-      <h3>ルールを書くのに適した場所</h3>
-      <p>詳細説明が設定されていません。</p>
     federation_hint_html: "%{instance} のアカウントひとつでどんなMastodon互換サーバーのユーザーでもフォローできるでしょう。"
     generic_description: "%{domain} は、Mastodon サーバーの一つです"
     get_apps: モバイルアプリを試す
@@ -37,6 +34,13 @@ ja:
     status_count_before: トゥート数
     tagline: Follow friends and discover new ones
     terms: 利用規約
+    unavailable_content: 制限中のサーバー
+    unavailable_content_description:
+      reason: '制限理由:'
+      rejecting_media: このサーバーからのメディアファイルは受信されず、サムネイルも表示されません。表示するにはクリックしてそのサーバーに直接アクセスする必要があります。
+      silenced: このサーバーからの投稿は相手をフォローしてもあなたのホームタイムライン以外には表示されません。
+      suspended: このサーバーからは誰もフォローできません。このサーバーからのデータは受信されず、やりとりもされません。
+    unavailable_content_html: 通常 Mastodon では連合先のどんなサーバーのユーザーとでもやりとりできます。ただし次のサーバーには例外が設定されています。
     user_count_after:
       other: 人
     user_count_before: ユーザー数
@@ -221,10 +225,12 @@ ja:
       deleted_status: "(削除済)"
       title: 操作履歴
     custom_emojis:
+      assign_category: カテゴリーを割り当て
       by_domain: ドメイン
       copied_msg: 絵文字のコピーをローカルに作成しました
       copy: コピー
       copy_failed_msg: 絵文字のコピーをローカルに作成できませんでした
+      create_new_category: カテゴリーを作成
       created_msg: 絵文字の追加に成功しました!
       delete: 削除
       destroyed_msg: 絵文字の削除に成功しました!
@@ -232,8 +238,10 @@ ja:
       disabled_msg: 絵文字を無効化しました
       emoji: 絵文字
       enable: 有効化
+      enabled: 有効
       enabled_msg: 絵文字を有効化しました
       image_hint: 50KBまでのPNG画像を利用できます
+      list: 表示
       listed: 収載
       new:
         title: 新規カスタム絵文字の追加
@@ -241,6 +249,8 @@ ja:
       shortcode: ショートコード
       shortcode_hint: 2文字以上の半角英数字とアンダーバーのみ利用できます
       title: カスタム絵文字
+      uncategorized: 未分類
+      unlist: 非表示
       unlisted: 未収載
       update_failed_msg: 絵文字を更新できませんでした
       updated_msg: 絵文字の更新に成功しました!
@@ -370,6 +380,7 @@ ja:
       pending: リレーサーバーの承認待ちです
       save_and_enable: 保存して有効にする
       setup: リレー接続を設定する
+      signatures_not_enabled: セキュアモードまたはホワイトリストモードが有効の場合、リレーは正常に動作しません
       status: ステータス
       title: リレー
     report_notes:
@@ -418,6 +429,9 @@ ja:
       custom_css:
         desc_html: 全ページに適用されるCSSの編集
         title: カスタムCSS
+      default_noindex:
+        desc_html: この設定を変更していない全ユーザーに影響します
+        title: デフォルトで検索エンジンによるインデックスを拒否する
       domain_blocks:
         all: 誰でも許可
         disabled: 誰も許可しない
@@ -509,6 +523,10 @@ ja:
       context: 表示先
       directory: ディレクトリに使用
       in_directory: "%{count} 人がディレクトリに使用"
+      last_active: 最近使われた順
+      most_popular: 使用頻度順
+      most_recent: 新着順
+      name: ハッシュタグ
       review: 審査状況
       reviewed: 審査済み
       title: ハッシュタグ
@@ -534,6 +552,12 @@ ja:
     new_trending_tag:
       body: 'ハッシュタグ #%{name} が本日のトレンドになっていますが、審査がまだ行われていないためトレンドタグには表示されていません。一度許可すれば次回からこの操作は不要です。'
       subject: "%{instance} で新しいハッシュタグ (#%{name}) が審査待ちです"
+  aliases:
+    add_new: エイリアスを作成
+    created_msg: エイリアスを作成しました。これで以前のアカウントから引っ越しを開始できます。
+    deleted_msg: エイリアスを解除しました。そのアカウントからは引っ越しできなくなります。
+    hint_html: 他のアカウントからこのアカウントにフォロワーを引き継いで引っ越したい場合、ここでエイリアスを作成しておく必要があります。エイリアス自体は<strong>無害で、取り消す</strong>ことができます。<strong>引っ越しは以前のアカウント側から開始する必要があります</strong>。
+    remove: エイリアスを解除
   appearance:
     advanced_web_interface: 上級者向け UI
     advanced_web_interface_hint: ディスプレイを幅いっぱいまで活用したい場合、上級者向け UI をおすすめします。ホーム、通知、連合タイムライン、更にはリストやハッシュタグなど、様々な異なるカラムから望む限りの情報を一度に受け取れるような設定が可能になります。
@@ -563,6 +587,10 @@ ja:
     checkbox_agreement_without_rules_html: <a href="%{terms_path}" target="_blank">利用規約</a> に同意します
     delete_account: アカウントの削除
     delete_account_html: アカウントを削除したい場合、<a href="%{path}">こちら</a> から手続きが行えます。削除する前に、確認画面があります。
+    description:
+      prefix_invited_by_user: "@%{name} があなたをこの Mastodon サーバーに招待しました"
+      prefix_sign_up: 今すぐ Mastodon に登録しましょう!
+      suffix: アカウントがあれば、どんな Mastodon 互換サーバーのユーザーでもフォローしたりメッセージをやり取りできるようになります!
     didnt_get_confirmation: 確認メールを受信できませんか?
     forgot_password: パスワードをお忘れですか?
     invalid_reset_password_token: パスワードリセットトークンが正しくないか期限切れです。もう一度リクエストしてください。
@@ -589,6 +617,7 @@ ja:
       confirming: メールアドレスの確認が完了するのを待っています。
       functional: アカウントは完全に機能しています。
       pending: あなたの申請は現在サーバー管理者による審査待ちです。これにはしばらくかかります。申請が承認されるとメールが届きます。
+      redirecting_to: アカウントは %{acct} に引っ越し設定されているため非アクティブになっています。
     trouble_logging_in: ログインできませんか?
   authorize_follow:
     already_following: あなたは既にこのアカウントをフォローしています
@@ -601,6 +630,11 @@ ja:
       return: ユーザーのプロフィールを見る
       web: Web を開く
     title: "%{acct} をフォロー"
+  challenge:
+    confirm: 続行する
+    hint_html: 以後 1 時間はパスワードの再入力を求めません
+    invalid_password: パスワードが間違っています
+    prompt: 続行するにはパスワードを入力してください
   datetime:
     distance_in_words:
       about_x_hours: "%{count}時間"
@@ -616,30 +650,26 @@ ja:
       x_months: "%{count}月"
       x_seconds: "%{count}秒"
   deletes:
+    challenge_not_passed: 入力された情報は正しくありません
     confirm_password: 本人確認のため、現在のパスワードを入力してください
+    confirm_username: 確認のためユーザー名を入力してください
     proceed: アカウントを削除する
     success_msg: アカウントは正常に削除されました
+    warning:
+      before: '続行する前に、次の点を再度確認してください:'
+      caches: 削除しても他のサーバーに残り続ける場合があります
+      data_removal: あなたの投稿やその他のデータはこのサーバーから完全に削除されます
+      email_change_html: アカウントを削除しなくても<a href="%{path}">メールアドレスを変更</a>できます
+      email_contact_html: それでも届かない場合、<a href="mailto:%{email}">%{email}</a> までメールで問い合わせてください
+      email_reconfirmation_html: 確認のメールが届かない場合、<a href="%{path}">もう一度申請</a>できます。
+      irreversible: アカウントを元に戻したり復活させることはできません
+      more_details_html: 詳しくは<a href="%{terms_path}">プライバシーポリシー</a>をご覧ください。
+      username_available: あなたのユーザー名は再利用できるようになります
+      username_unavailable: あなたのユーザー名は引き続き利用できません
   directories:
     directory: ディレクトリ
     explanation: 関心を軸にユーザーを発見しよう
     explore_mastodon: "%{title}を探索"
-  domain_blocks:
-    blocked_domains: ドメインブロックリスト
-    description: "%{instance} が連合を制限または拒否しているサーバーのリストです。"
-    domain: ドメイン
-    media_block: メディアを拒否
-    no_domain_blocks: "(ドメインブロックなし)"
-    severity: 重大性
-    severity_legend:
-      media_block: サーバーから送信されるメディアファイルは取得も保存もされず、またユーザーには表示されません。
-      silence: サイレンスされたサーバーのアカウントは検索やフォロー、交流することができますが、トゥートは公開タイムラインに表示されません。またフォローしていないユーザーには通知が届きません。
-      suspension: 停止されたサーバーからのコンテンツは保存も表示もされず、また送信もされません。停止されたサーバーからの交流は拒否されます。
-      suspension_disclaimer: 停止されたサーバーでもこのサーバーから公開コンテンツを取得することがあります。
-      title: 重大性
-    show_rationale: コメントを表示
-    silence: サイレンス
-    suspension: 停止
-    title: "%{instance} のドメインブロックリスト"
   domain_validator:
     invalid_domain: は無効なドメイン名です
   errors:
@@ -705,6 +735,7 @@ ja:
     all: すべて
     changes_saved_msg: 正常に変更されました!
     copy: コピー
+    no_batch_actions_available: 利用可能なバッチアクションはありません
     order_by: 並び順
     save_changes: 変更を保存
     use_this: これを使う
@@ -775,9 +806,31 @@ ja:
       too_many: 追加できるファイルは4つまでです
   migrations:
     acct: 引っ越し先の ユーザー名@ドメイン
-    currently_redirecting: 'あなたのプロフィールは引っ越し先が設定されています:'
-    proceed: 保存
-    updated_msg: アカウントの引っ越し設定を更新しました!
+    cancel: 引っ越しを取り消す
+    cancel_explanation: 引っ越しを取り消すと現在のアカウントが再度有効化されますが、引き継がれたフォロワーは戻されません。
+    cancelled_msg: 引っ越し設定を取り消しました。
+    errors:
+      already_moved: は既に引っ越したアカウントと同じです
+      missing_also_known_as: はこのアカウントとエイリアスの設定がされていません
+      move_to_self: 同じアカウントに引っ越すことはできません
+      not_found: 見つかりませんでした
+      on_cooldown: クールダウン期間中です
+    followers_count: 引き継がれるフォロワー
+    incoming_migrations: 別のアカウントから引っ越す
+    incoming_migrations_html: 別のアカウントからこのアカウントに引っ越すには、まず<a href="%{path}">アカウントエイリアスを作成</a>する必要があります。
+    moved_msg: アカウントは %{acct} に引っ越し設定されており、フォロワーは引っ越し先に引き継がれています。
+    not_redirecting: アカウントは現在引っ越し設定されていません。
+    on_cooldown: あなたは最近アカウントを引っ越ししています。この機能は %{count} 日後に再度利用できるようになります。
+    past_migrations: 過去の引っ越し
+    proceed_with_move: フォロワーを引き継ぐ
+    redirecting_to: アカウントは %{acct} に引っ越し設定されています。
+    warning:
+      backreference_required: まずは引っ越し先のアカウントでこのアカウントに対しエイリアスを作成する必要があります
+      before: '続行する前に、次の点を再度確認してください:'
+      cooldown: 引っ越し後はクールダウン期間があります。その間再度引っ越すことはできません
+      disabled_account: 引っ越すと現在のアカウントの機能は完全には利用できなくなります。ただしデータのエクスポートと再有効化は利用できます。
+      followers: この操作により、すべてのフォロワーを現在のアカウントから新しいアカウントに引き継ぎます。
+      other_data: その他のデータは自動的に引き継がれません
   moderation:
     title: モデレーション
   notification_mailer:
@@ -920,6 +973,7 @@ ja:
   settings:
     account: アカウント
     account_settings: セキュリティ
+    aliases: アカウントエイリアス
     appearance: 外観
     authorized_apps: 認証済みアプリ
     back: Mastodon に戻る
@@ -1071,7 +1125,7 @@ ja:
       default: "%Y年%m月%d日 %H:%M"
       month: "%Y年 %b"
   two_factor_authentication:
-    code_hint: 確認するには認証アプリで表示されたコードを入力してください
+    code_hint: 続行するには認証アプリで表示されたコードを入力してください
     description_html: "<strong>二段階認証</strong>を有効にするとログイン時、認証アプリからコードを入力する必要があります。"
     disable: 無効
     enable: 有効
diff --git a/config/locales/ka.yml b/config/locales/ka.yml
index 93cc8ec5a..c921fa56f 100644
--- a/config/locales/ka.yml
+++ b/config/locales/ka.yml
@@ -11,9 +11,6 @@ ka:
     contact_missing: არაა დაყენებული
     contact_unavailable: მიუწ.
     documentation: დოკუმენტაცია
-    extended_description_html: |
-      <h3>კარგი ადგილი წესებისთვის</h3>
-      <p>განვრცობილი აღწერილობა ჯერ არ შექმნილა.</p>
     generic_description: "%{domain} ერთი სერვერია ქსელში"
     hosted_on: მასტოდონს მასპინძლობს %{domain}
     learn_more: გაიგე მეტი
@@ -531,9 +528,6 @@ ka:
       too_many: თან ვერ დაურთავთ 4 ფაილზე მეტს
   migrations:
     acct: username@domain ახალი ანგარიშის
-    currently_redirecting: 'თქვენი პროფილი გამართულია მოახდინოს გადამისამართება მისამართზე:'
-    proceed: შენახვა
-    updated_msg: თქვენი ანგარიშის მიგრაციის პარამეტრები წარმატეებით დამახსოვრდა!
   moderation:
     title: მოდერაცია
   notification_mailer:
diff --git a/config/locales/kk.yml b/config/locales/kk.yml
index 3658b2293..84cbdd294 100644
--- a/config/locales/kk.yml
+++ b/config/locales/kk.yml
@@ -10,9 +10,6 @@ kk:
     contact_missing: Бапталмаған
     contact_unavailable: Белгісіз
     documentation: Құжаттама
-    extended_description_html: |
-      <h3>Ережелерге арналған жақсы орын</h3>
-      <p>Әлі ештеңе жазылмапты</p>
     generic_description: "%{domain} желідегі серверлердің бірі"
     hosted_on: Mastodon орнатылған %{domain} доменінде
     learn_more: Көбірек білу
@@ -624,9 +621,6 @@ kk:
       too_many: 4 файлдан артық қосылмайды
   migrations:
     acct: жаңа аккаунт үшін username@domain
-    currently_redirecting: 'Профиліңіз көшіріледі:'
-    proceed: Сақтау
-    updated_msg: Аккаунт көшіруіңіз сәтті аяқталды!
   moderation:
     title: Модерация
   notification_mailer:
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index fc9fa7b80..5e6d87869 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -17,9 +17,6 @@ ko:
     contact_unavailable: 없음
     discover_users: 유저 발견하기
     documentation: 문서
-    extended_description_html: |
-      <h3>룰을 작성하는 장소</h3>
-      <p>아직 설명이 작성되지 않았습니다.</p>
     federation_hint_html: "%{instance}에 계정을 만드는 것으로 모든 마스토돈 서버, 그리고 호환 되는 모든 서버의 사용자를 팔로우 할 수 있습니다."
     generic_description: "%{domain} 은 네트워크에 있는 한 서버입니다"
     get_apps: 모바일 앱 사용해 보기
@@ -37,6 +34,13 @@ ko:
     status_count_before: 툿 수
     tagline: 친구들을 팔로우 하고 새로운 사람들도 만나기
     terms: 이용약관
+    unavailable_content: 이용 불가능한 컨텐츠
+    unavailable_content_description:
+      reason: '이유:'
+      rejecting_media: 이 서버의 미디어 파일들은 처리되지 않고 썸네일또한 보이지 않게 됩니다. 수동으로 클릭하여 해당 서버로 가게 됩니다.
+      silenced: 이 서버의 게시물은 작성자를 팔로우 한 경우에만 홈 피드에 나타나며 이를 제외한 어디에도 나타나지 않습니다.
+      suspended: 이 서버의 아무도 팔로우 할 수 없으며, 어떤 데이터도 처리되거나 저장 되지 않고 데이터가 교환 되지도 않습니다.
+    unavailable_content_html: 마스토돈은 일반적으로 연합우주에 있는 어떤 서버의 유저와도 게시물을 보고 응답을 할 수 있도록 허용합니다. 다음 항목들은 특정한 서버에 대해 만들어 진 예외사항입니다.
     user_count_after:
       other: 명
     user_count_before: 사용자 수
@@ -221,10 +225,12 @@ ko:
       deleted_status: "(삭제됨)"
       title: 감사 기록
     custom_emojis:
+      assign_category: 분류 지정
       by_domain: 도메인
       copied_msg: 성공적으로 에모지의 로컬 복사본을 생성했습니다
       copy: 복사
       copy_failed_msg: 에모지의 로컬 복사본을 만드는 데 실패하였습니다
+      create_new_category: 분류 생성
       created_msg: 에모지가 성공적으로 생성되었습니다!
       delete: 삭제
       destroyed_msg: 에모지가 성공적으로 삭제되었습니다!
@@ -232,8 +238,10 @@ ko:
       disabled_msg: 성공적으로 비활성화하였습니다
       emoji: 에모지
       enable: 활성화
+      enabled: 활성됨
       enabled_msg: 성공적으로 활성화하였습니다
       image_hint: 50KB 이하의 PNG
+      list: 목록
       listed: 목록에 실림
       new:
         title: 새 커스텀 에모지 추가
@@ -241,6 +249,8 @@ ko:
       shortcode: 짧은 코드
       shortcode_hint: 최소 2글자, 영문자, 숫자, _만 사용 가능
       title: 커스텀 에모지
+      uncategorized: 분류되지 않음
+      unlist: 목록에서 제거
       unlisted: 목록에 없음
       update_failed_msg: 에모지를 업데이트 할 수 없습니다
       updated_msg: 에모지가 성공적으로 업데이트 되었습니다!
@@ -372,6 +382,7 @@ ko:
       pending: 릴레이의 승인 대기중
       save_and_enable: 저장하고 활성화
       setup: 릴레이 연결 설정
+      signatures_not_enabled: 시큐어모드나 화이트리스트모드를 사용하고 있다면 릴레이는 제대로 동작하지 않을 것입니다
       status: 상태
       title: 릴레이
     report_notes:
@@ -420,6 +431,9 @@ ko:
       custom_css:
         desc_html: 모든 페이지에 적용할 CSS
         title: 커스텀 CSS
+      default_noindex:
+        desc_html: 이 설정을 바꾸지 않은 모든 유저들에게 적용 됩니다
+        title: 유저들이 기본적으로 검색엔진에 인덱싱 되지 않도록 합니다
       domain_blocks:
         all: 모두에게
         disabled: 아무에게도 안 함
@@ -511,11 +525,15 @@ ko:
       context: 문맥
       directory: 디렉토리에 있음
       in_directory: 디렉토리에 %{count}개 있음
+      last_active: 최근 활동
+      most_popular: 최고 인기
+      most_recent: 최신
+      name: 해시태그
       review: 심사 상태
       reviewed: 심사 됨
       title: 해시태그
       trending_right_now: 지금 유행 중
-      unique_uses_today: 오늘 %{count}개의 포스팅
+      unique_uses_today: 오늘 %{count}명이 포스팅
       unreviewed: 심사 되지 않음
       updated_msg: 해시태그 설정이 성공적으로 갱신되었습니다
     title: 관리
@@ -536,6 +554,12 @@ ko:
     new_trending_tag:
       body: "#%{name}가 오늘 유행하고 있습니다, 하지만 심사 된 적이 없습니다. 허용하지 않는 한 공개적으로 나타나지 않습니다. 또는 그냥 저장을 눌러 더이상 나타나지 않게 할 수 있습니다."
       subject: 새 해시태그가 %{instance}에서 심사 대기 중입니다(#%{name})
+  aliases:
+    add_new: 별칭 만들기
+    created_msg: 새 별칭이 성공적으로 만들어졌습니다. 이제 기존 계정에서 이주를 시작할 수 있습니다.
+    deleted_msg: 성공적으로 별칭을 삭제했습니다. 해당 계정에서 이 계정으로의 이주는 더이상 가능하지 않습니다.
+    hint_html: 다른 계정에서 이 계정으로 옮기길 원하는 경우, 여기에서 별칭을 만들 수 있습니다, 기존 계정의 팔로워를 이쪽으로 옮기고 싶은 경우 필요한 과정입니다. 이 행동 자체는 <strong>해롭지 않고 되돌리기가 가능합니다</strong>.<strong>계정 이주는 이전 계정에서 착수하게 됩니다</strong>
+    remove: 별칭 연결 끊기
   appearance:
     advanced_web_interface: 고급 웹 인터페이스
     advanced_web_interface_hint: '화면의 가로폭을 가득 채우고 싶다면, 고급 웹 인터페이스는 한 번에 여러 정보를 볼 수 있도록 여러 컬럼을 설정할 수 있도록 합니다: 홈, 알림, 연합타임라인, 리스트, 해시태그 등'
@@ -565,6 +589,10 @@ ko:
     checkbox_agreement_without_rules_html: <a href="%{terms_path}" target="_blank">이용 약관</a>에 동의합니다
     delete_account: 계정 삭제
     delete_account_html: 계정을 삭제하고 싶은 경우, <a href="%{path}">여기서</a> 삭제할 수 있습니다. 삭제 전 확인 화면이 표시됩니다.
+    description:
+      prefix_invited_by_user: "@%{name} 님이 당신을 이 마스토돈 서버로 초대했습니다!"
+      prefix_sign_up: 마스토돈에 가입하세요!
+      suffix: 계정 하나로 사람들을 팔로우 하고, 게시물을 작성하며 마스토돈을 포함한 다른 어떤 서버의 유저와도 메시지를 주고 받을 수 있습니다!
     didnt_get_confirmation: 확인 메일을 받지 못하셨습니까?
     forgot_password: 비밀번호를 잊어버리셨습니까?
     invalid_reset_password_token: 암호 리셋 토큰이 올바르지 못하거나 기간이 만료되었습니다. 다시 요청해주세요.
@@ -591,6 +619,7 @@ ko:
       confirming: 이메일 확인 과정이 완료되기를 기다리는 중.
       functional: 계정이 완벽이 작동합니다.
       pending: 당신의 가입 신청은 스태프의 검사를 위해 대기중입니다. 이것은 시간이 다소 소요됩니다. 가입 신청이 승인 될 경우 이메일을 받게 됩니다.
+      redirecting_to: 계정이 %{acct}로 리다이렉트 중이기 때문에 비활성 상태입니다.
     trouble_logging_in: 로그인 하는데 문제가 있나요?
   authorize_follow:
     already_following: 이미 이 계정을 팔로우 하고 있습니다
@@ -603,6 +632,11 @@ ko:
       return: 유저 프로필 보기
       web: 웹으로 가기
     title: "%{acct} 를 팔로우"
+  challenge:
+    confirm: 계속
+    hint_html: "<strong>팁:</strong>한 시간동안 다시 비밀번호를 묻지 않을 겁니다."
+    invalid_password: 잘못된 비밀번호
+    prompt: 계속하려면 암호 확인
   datetime:
     distance_in_words:
       about_x_hours: "%{count}시간"
@@ -618,30 +652,26 @@ ko:
       x_months: "%{count}월"
       x_seconds: "%{count}초"
   deletes:
+    challenge_not_passed: 입력한 정보가 올바르지 않습니다
     confirm_password: 본인 확인을 위해 현재 사용 중인 암호를 입력해 주십시오
+    confirm_username: 절차를 진행하려면 당신의 사용자명을 입력하세요
     proceed: 계정 삭제
     success_msg: 계정이 성공적으로 삭제되었습니다
+    warning:
+      before: '진행하기 전, 주의사항을 꼼꼼히 읽어보세요:'
+      caches: 다른 서버에 캐싱 된 정보들은 남아있을 수 있습니다
+      data_removal: 당신의 게시물과 다른 정보들은 영구적으로 삭제 됩니다
+      email_change_html: 계정을 지우지 않고도 <a href="%{path}">이메일 주소를 수정할 수 있습니다</a>
+      email_contact_html: 아직 도착하지 않았다면, <a href="mailto:%{email}">%{email}</a>에 메일을 보내 도움을 요청할 수 있습니다
+      email_reconfirmation_html: 아직 확인 메일이 도착하지 않은 경우, <a href="%{path}">다시 요청할 수 있습니다</a>
+      irreversible: 계정을 복구하거나 다시 사용할 수 없게 됩니다
+      more_details_html: 더 자세한 정보는, <a href="%{terms_path}">개인정보 정책</a>을 참고하세요.
+      username_available: 당신의 계정명은 다시 사용할 수 있게 됩니다
+      username_unavailable: 당신의 계정명은 앞으로 사용할 수 없습니다
   directories:
     directory: 프로필 디렉토리
     explanation: 관심사에 대한 유저들을 발견합니다
     explore_mastodon: "%{title} 탐사하기"
-  domain_blocks:
-    blocked_domains: 제한 되거나 차단 된 도메인 목록
-    description: 이것은 %{instance}가 제한하거나 연합을 거부한 서버들의 목록입니다.
-    domain: 도메인
-    media_block: 미디어 차단
-    no_domain_blocks: "(도메인 차단 없음)"
-    severity: 심각도
-    severity_legend:
-      media_block: 이 서버의 미디어는 불러오거나, 저장 되거나, 유저에게 보여지지 않습니다.
-      silence: 침묵 된 서버의 계정은 발견 되고, 팔로우 하고, 그들과 상호작용 할 수 있습니다, 그러나 그들의 툿은 툿 공개 타임라인에 나타나지 않으며 그들에게서 오는 알림은 그들을 팔로우 하지 않는 로컬 유저에게는 전달되지 않습니다.
-      suspension: 정지 된 서버의 어떤 콘텐츠도 저장 되거나 보여지거나 하지 않고 어떤 콘텐츠도 그 서버로 전달 되지 않습니다. 정지 된 서버에서의 상호작용은 무시됩니다.
-      suspension_disclaimer: 정지 된 서버는 때때로 이 서버의 공개 콘텐츠를 받아 갈 수도 잇습니다.
-      title: 심각도
-    show_rationale: 사유 보여주기
-    silence: 침묵
-    suspension: 정지
-    title: "%{instance}의 차단한 인스턴스 목록"
   domain_validator:
     invalid_domain: 올바른 도메인 네임이 아닙니다
   errors:
@@ -707,6 +737,7 @@ ko:
     all: 모두
     changes_saved_msg: 정상적으로 변경되었습니다!
     copy: 복사
+    no_batch_actions_available: 이 페이지에서 수행할 수 있는 일괄작업이 없습니다
     order_by: 순서
     save_changes: 변경 사항을 저장
     validation_errors:
@@ -776,9 +807,31 @@ ko:
       too_many: 최대 4개까지 첨부할 수 있습니다
   migrations:
     acct: 새 계정의 username@domain
-    currently_redirecting: '당신의 프로파일은 여기로 리디렉션 됩니다:'
-    proceed: 저장
-    updated_msg: 계정 이동 설정이 저장되었습니다!
+    cancel: 리디렉션 취소
+    cancel_explanation: 리다이렉트를 취소하면 현재 계정이 다시 활성화 됩니다, 새 계정으로 이동한 팔로워를 되찾을 수는 없습니다.
+    cancelled_msg: 리다이렉트를 성공적으로 취소했습니다.
+    errors:
+      already_moved: 이미 이동한 계정과 동일합니다
+      missing_also_known_as: 이 계정을 역으로 참조하지 않고 있습니다
+      move_to_self: 현재 계정은 사용할 수 없습니다
+      not_found: 찾을 수 없습니다
+      on_cooldown: 쿨다운 기간입니다
+    followers_count: 이주 될 팔로워들
+    incoming_migrations: 다른 계정으로부터 옮기기
+    incoming_migrations_html: 다른 계정을 이 계정으로 이주하고 싶은 경우, 먼저 <a href="%{path}">계정 별칭을 만들어야 합니다</a>.
+    moved_msg: 당신의 계정은 %{acct}로 리다이렉트 되고 있으며 팔로워들은 이주 될 것입니다.
+    not_redirecting: 현재 이 계정은 어디로도 리다이렉트 되고 있지 않습니다.
+    on_cooldown: 당신은 최근에 이미 계정을 이동했습니다. 이 기능은 %{count} 일 후에 다시 이용 가능합니다.
+    past_migrations: 이전 마이그레이션
+    proceed_with_move: 팔로워 이동
+    redirecting_to: 당신의 계정은 %{acct} 로 리다이렉트됩니다.
+    warning:
+      backreference_required: 새 계정은 이 계정으로 역참조를 하도록 설정되어 있어야 합니다
+      before: '진행하기 전, 주의사항을 꼼꼼히 읽어보세요:'
+      cooldown: 이주 뒤에는 새로운 이주를 하지 못하는 쿨다운 기간이 존재합니다
+      disabled_account: 이 계정은 완전한 사용이 불가능하게 됩니다. 하지만, 데이터 내보내기나 재활성화를 위해 접근할 수 있습니다.
+      followers: 이 행동은 현재 계정의 모든 팔로워를 새 계정으로 이동시킵니다
+      other_data: 다른 어떤 데이터도 자동적으로 옮겨지지 않을 것입니다
   moderation:
     title: 모더레이션
   notification_mailer:
@@ -921,6 +974,7 @@ ko:
   settings:
     account: 계정
     account_settings: 계정 설정
+    aliases: 계정 별명
     appearance: 외관
     authorized_apps: 인증된 애플리케이션
     back: 돌아가기
diff --git a/config/locales/lt.yml b/config/locales/lt.yml
index 7aed705cb..e1471eed0 100644
--- a/config/locales/lt.yml
+++ b/config/locales/lt.yml
@@ -9,9 +9,6 @@ lt:
     contact: Kontaktai
     contact_missing: Nenustatyta
     documentation: Dokumentacija
-    extended_description_html: |
-      <h3>Taisyklės</h3>
-      <p>Ilgas aprašymas dar nėra sudartyas</p>
     generic_description: "%{domain} yra vienas serveris tinkle"
     hosted_on: Mastodon palaikomas naudojantis %{domain} talpinimu
     learn_more: Daugiau
@@ -597,9 +594,6 @@ lt:
       too_many: Negalima pridėti daugiau nei 4 failų
   migrations:
     acct: slapyvardis@domenas naujam vartotojui
-    currently_redirecting: 'Jūsų profilis nustatytas nukreipimui į:'
-    proceed: Išsaugoti
-    updated_msg: Jūsų paskyros migracijos nustatymai sėkmingai pakeisti!
   moderation:
     title: Moderacija
   notification_mailer:
diff --git a/config/locales/ms.yml b/config/locales/ms.yml
index 4573d53dd..b77a1fd92 100644
--- a/config/locales/ms.yml
+++ b/config/locales/ms.yml
@@ -10,9 +10,6 @@ ms:
     contact_missing: Tidak ditetapkan
     contact_unavailable: Tidak tersedia
     documentation: Pendokumenan
-    extended_description_html: |
-      <h3>Tempat sesuai untuk peraturan</h3>
-      <p>Kenyataan penuh masih belum ditetapkan.</p>
     generic_description: "%{domain} ialah salah sebuah pelayan dalam rangkaian Mastodon"
     hosted_on: Mastodon dihoskan di %{domain}
     learn_more: Ketahui lebih lanjut
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 9298e0ae0..f4501a865 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -17,13 +17,13 @@ nl:
     contact_unavailable: n.v.t
     discover_users: Gebruikers ontdekken
     documentation: Documentatie
-    extended_description_html: |
-      <h3>Een goede plek voor richtlijnen</h3>
-      <p>De uitgebreide omschrijving is nog niet ingevuld.</p>
     federation_hint_html: Met een account op %{instance} ben je in staat om mensen die zich op andere Mastodonservers (en op andere plekken) bevinden te volgen.
     generic_description: "%{domain} is een server in het Mastodonnetwerk"
     get_apps: Mobiele apps
     hosted_on: Mastodon op %{domain}
+    instance_actor_flash: 'Dit account is een virtuel actor die wordt gebruikt om de server zelf te vertegenwoordigen en is geen individuele gebruiker. Het wordt voor federatiedoeleinden gebruikt en moet niet worden geblokkeerd, tenzij je de hele server wil blokkeren. In zo''n geval dien je echter een domeinblokkade te gebruiken.
+
+'
     learn_more: Meer leren
     privacy_policy: Privacybeleid
     see_whats_happening: Kijk wat er aan de hand is
@@ -35,6 +35,13 @@ nl:
     status_count_before: Zij schreven
     tagline: Vrienden volgen en nieuwe ontdekken
     terms: Gebruiksvoorwaarden
+    unavailable_content: Niet beschikbare inhoud
+    unavailable_content_description:
+      reason: 'Reden:'
+      rejecting_media: Mediabestanden van deze server worden niet verwerkt en er worden geen thumbnails getoond. Je moet handmatig naar deze server doorklikken om de mediabestanden te kunnen bekijken.
+      silenced: Toots van deze server worden nergens weergegeven, behalve op jouw eigen starttijdlijn wanneer je het account volgt.
+      suspended: Je bent niet in staat om iemand van deze server te volgen, en er worden geen gegevens van deze server verwerkt of opgeslagen, en met deze server uitgewisseld.
+    unavailable_content_html: Met Mastodon kun je in het algemeen berichten bekijken van en communiceren met gebruikers van elke andere server in de fediverse. Dit zijn de uitzonderingen die door deze server zijn gemaakt en expliciet alleen hier gelden.
     user_count_after:
       one: gebruiker
       other: gebruikers
@@ -42,6 +49,8 @@ nl:
     what_is_mastodon: Wat is Mastodon?
   accounts:
     choices_html: 'Aanbevelingen van %{name}:'
+    endorsements_hint: Je kunt mensen die je volgt in de webomgeving aanbevelen, waarna ze dan hier zullen verschijnen.
+    featured_tags_hint: Je kunt specifieke hashtags uitlichten, waarna ze dan hier zullen verschijnen.
     follow: Volgen
     followers:
       one: Volger
@@ -53,6 +62,7 @@ nl:
     media: Media
     moved_html: "%{name} is verhuisd naar %{new_profile_link}:"
     network_hidden: Deze informatie is niet beschikbaar
+    never_active: Nooit
     nothing_here: Hier is niets!
     people_followed_by: Mensen die %{name} volgen
     people_who_follow: Mensen die %{name} volgen
@@ -219,10 +229,12 @@ nl:
       deleted_status: "(verwijderde toot}"
       title: Auditlog
     custom_emojis:
+      assign_category: Categorie toewijzen
       by_domain: Domein
       copied_msg: Lokale kopie van emoji maken geslaagd
       copy: Kopiëren
       copy_failed_msg: Kan geen lokale kopie van deze emoji maken
+      create_new_category: Nieuwe categorie toevoegen
       created_msg: Aanmaken van emoji geslaagd!
       delete: Verwijderen
       destroyed_msg: Verwijderen van emoji geslaagd!
@@ -230,8 +242,10 @@ nl:
       disabled_msg: Uitschakelen van deze emoji geslaagd
       emoji: Emoji
       enable: Inschakelen
+      enabled: Ingeschakeld
       enabled_msg: Inschakelen van deze emoji geslaagd
       image_hint: PNG van max. 50KB
+      list: In lijst
       listed: Weergegeven
       new:
         title: Lokale emoji toevoegen
@@ -239,12 +253,14 @@ nl:
       shortcode: Verkorte code
       shortcode_hint: Tenminste 2 tekens (alleen alfanumeriek en underscores)
       title: Lokale emoji’s
+      uncategorized: Niet gecategoriseerd
+      unlist: Niet in lijst
       unlisted: Niet weergegeven
       update_failed_msg: Deze emoji kon niet worden bijgewerkt
       updated_msg: Bijwerken van emoji is geslaagd!
       upload: Uploaden
     dashboard:
-      authorized_fetch_mode: Geautoriseerde ophaalmodus
+      authorized_fetch_mode: Veilige modus
       backlog: achterstallige taken
       config: Configuratie
       feature_deletions: Verwijderen van account
@@ -370,6 +386,7 @@ nl:
       pending: Aan het wachten op toestemming van de relayserver
       save_and_enable: Opslaan en inschakelen
       setup: Een verbinding met een relayserver maken
+      signatures_not_enabled: Federatierelays werken niet goed wanneer de veilige modus of de witte lijstmodus is ingeschakeld
       status: Status
       title: Relayservers
     report_notes:
@@ -418,6 +435,9 @@ nl:
       custom_css:
         desc_html: Het uiterlijk van deze server met CSS aanpassen
         title: Aangepaste CSS
+      default_noindex:
+        desc_html: Heeft invloed op alle gebruikers die deze instelling niet zelf hebben veranderd
+        title: Toots van gebruikers standaard niet door zoekmachines laten indexeren
       domain_blocks:
         all: Naar iedereen
         disabled: Naar niemand
@@ -475,6 +495,9 @@ nl:
         desc_html: Je kan hier jouw eigen privacybeleid, gebruiksvoorwaarden en ander juridisch jargon kwijt. Je kan HTML gebruiken
         title: Aangepaste gebruiksvoorwaarden
       site_title: Naam Mastodonserver
+      spam_check_enabled:
+        desc_html: Mastodon kan accounts die herhaaldelijk ongevraagde berichten versturen automatisch negeren of rapporteren. Het is mogelijk dat er foutpositieven tussen zitten.
+        title: Automatische spambestrijding
       thumbnail:
         desc_html: Gebruikt als voorvertoning voor OpenGraph en de API. 1200x630px aanbevolen
         title: Thumbnail Mastodonserver
@@ -483,6 +506,7 @@ nl:
         title: Tijdlijn op de voorpagina tonen
       title: Server-instellingen
       trends:
+        desc_html: Eerder beoordeelde hashtags die op dit moment trending zijn openbaar tonen
         title: Trending hashtags
     statuses:
       back_to_account: Terug naar accountpagina
@@ -499,16 +523,23 @@ nl:
       title: Toots van account
       with_media: Met media
     tags:
-      accounts_today: Aantal unieke keren vandaag gebruikt
-      accounts_week: Aantal unieke keren deze week gebruikt
+      accounts_today: Aantal verschillende keren vandaag gebruikt
+      accounts_week: Aantal verschillende keren deze week gebruikt
+      breakdown: Uitsplitsing van het gebruik van vandaag naar bron
       context: Context
       directory: In de gebruikersgids
       in_directory: "%{count} keer in de gebruikersgids"
+      last_active: Laatst actief
+      most_popular: Meest populair
+      most_recent: Meest recent
+      name: Hashtag
       review: Status beoordelen
       reviewed: Beoordeeld
       title: Hashtags
       trending_right_now: Op dit moment trending
+      unique_uses_today: "%{count} keer vandaag gebruikt"
       unreviewed: Niet beoordeeld
+      updated_msg: Instellingen hashtag succesvol bijgewerkt
     title: Beheer
     warning_presets:
       add_new: Nieuwe toevoegen
@@ -524,6 +555,15 @@ nl:
       body: "%{reporter} heeft %{target} gerapporteerd"
       body_remote: Iemand van %{domain} heeft %{target} gerapporteerd
       subject: Nieuwe rapportage op %{instance} (#%{id})
+    new_trending_tag:
+      body: 'De hashtag #%{name} is vandaag trending, maar is nog niet beoordeeld. Het wordt niet in het openbaar getoond alvorens je de hashtag goedkeurt. Je kunt ook het formulier zoals het nu is opslaan, waarna je er niks meer over zult horen.'
+      subject: Nieuwe hashtag te beoordelen op %{instance} (#%{name})
+  aliases:
+    add_new: Alias aanmaken
+    created_msg: Succesvol een nieuwe alias aangemaakt. Je kunt nu met de verhuizing vanaf het oude account beginnen.
+    deleted_msg: De alias is succesvol verwijderd. Verhuizen vanaf dat account naar dit account is niet meer mogelijk.
+    hint_html: Wanneer je vanaf een ander account naar dit account wilt verhuizen, kun je hier een alias aanmaken. Dit is nodig voordat je verder kunt gaan met het verhuizen van volgers van het oude naar dit nieuwe account. Deze actie is op zich <strong>ongevaarlijk en omkeerbaar</strong>. <strong>De accountmigratie wordt gestart vanaf het oude account</strong>.
+    remove: Alias ontkoppelen
   appearance:
     advanced_web_interface: Geavanceerde webomgeving
     advanced_web_interface_hint: 'Wanneer je van de hele schermbreedte gebruik wilt maken, stelt de geavanceerde webomgeving je in staat om meerdere verschillende kolommen te configureren. Hiermee kun je zoveel mogelijk informatie op hetzelfde moment bekijken, zoals: Start, meldingen, de globale tijdlijn, meerdere lijsten en hashtags.'
@@ -550,8 +590,13 @@ nl:
     apply_for_account: Een uitnodiging aanvragen
     change_password: Wachtwoord
     checkbox_agreement_html: Ik ga akkoord met de <a href="%{rules_path}" target="_blank">regels van deze server</a> en de <a href="%{terms_path}" target="_blank">gebruiksvoorwaarden</a>
+    checkbox_agreement_without_rules_html: Ik ga akkoord met de <a href="%{terms_path}" target="_blank">gebruiksvoorwaarden</a>
     delete_account: Account verwijderen
     delete_account_html: Wanneer je jouw account graag wilt verwijderen, kun je dat <a href="%{path}">hier doen</a>. We vragen jou daar om een bevestiging.
+    description:
+      prefix_invited_by_user: "@%{name} nodigt je hierbij uit om een account aan te maken op deze Mastodonserver!"
+      prefix_sign_up: Registreer je vandaag nog op Mastodon!
+      suffix: Met een account ben je in staat om mensen te volgen, berichten te plaatsen en uit te wisselen met mensen die zich op andere Mastodonservers bevinden en meer!
     didnt_get_confirmation: Geen bevestigingsinstructies ontvangen?
     forgot_password: Wachtwoord vergeten?
     invalid_reset_password_token: De code om jouw wachtwoord opnieuw in te stellen is verlopen. Vraag een nieuwe aan.
@@ -570,9 +615,15 @@ nl:
     security: Beveiliging
     set_new_password: Nieuw wachtwoord instellen
     setup:
+      email_below_hint_html: Wanneer onderstaand e-mailadres niet klopt, kun je dat hier veranderen. Je ontvangt dan hierna een bevestigingsmail.
+      email_settings_hint_html: De bevestigingsmail is verzonden naar %{email}. Wanneer dat e-mailadres niet klopt, kun je dat veranderen in je accountinstellingen.
       title: Instellen
     status:
       account_status: Accountstatus
+      confirming: Aan het wachten totdat de e-mail is bevestigd.
+      functional: Jouw account is volledig operationeel.
+      pending: Jouw aanvraag moet nog worden beoordeeld door een van onze medewerkers. Dit kan misschien eventjes duren. Je ontvangt een e-mail wanneer jouw aanvraag is goedgekeurd.
+      redirecting_to: Jouw account is inactief omdat het momenteel wordt doorverwezen naar %{acct}.
     trouble_logging_in: Problemen met inloggen?
   authorize_follow:
     already_following: Je volgt dit account al
@@ -585,6 +636,11 @@ nl:
       return: Profiel van deze gebruiker tonen
       web: Ga naar de webapp
     title: Volg %{acct}
+  challenge:
+    confirm: Doorgaan
+    hint_html: "<strong>Tip:</strong> We vragen jou het komende uur niet meer naar jouw wachtwoord."
+    invalid_password: Ongeldig wachtwoord
+    prompt: Bevestig wachtwoord om door te gaan
   datetime:
     distance_in_words:
       about_x_hours: "%{count}u"
@@ -600,28 +656,33 @@ nl:
       x_months: "%{count}ma"
       x_seconds: "%{count}s"
   deletes:
+    challenge_not_passed: De informatie die u hebt ingevoerd is ongeldig
     confirm_password: Voer jouw huidige wachtwoord in om jouw identiteit te bevestigen
+    confirm_username: Voer uw gebruikersnaam in om de procedure te bevestigen
     proceed: Account verwijderen
     success_msg: Jouw account is succesvol verwijderd
+    warning:
+      before: 'Lees deze tekst zorgvuldig voordat je verder gaat:'
+      caches: Toots en media die op andere servers zijn opgeslagen kunnen daar achterblijven
+      data_removal: Jouw toots en andere gegevens worden permanent verwijderd
+      email_change_html: Je kunt <a href="%{path}">je e-mailadres wijzigen</a> zonder dat je jouw account hoeft te verwijderen
+      email_contact_html: Wanneer het nog steeds niet aankomt, kun je voor hulp e-mailen naar <a href="mailto:%{email}">%{email}</a>
+      email_reconfirmation_html: Wanneer je de bevestigingsmail niet hebt ontvangen, kun je deze <a href="%{path}">opnieuw aanvragen</a>
+      irreversible: Je zult niet in staat zijn om jouw account te herstellen of te deactiveren
+      more_details_html: Zie het <a href="%{terms_path}">privacybeleid</a> voor meer informatie.
+      username_available: Jouw gebruikersnaam zal weer beschikbaar komen
+      username_unavailable: Jouw gebruikersnaam zal onbeschikbaar blijven
   directories:
     directory: Gebruikersgids
     explanation: Ontdek gebruikers aan de hand van hun interesses
     explore_mastodon: "%{title} verkennen"
-  domain_blocks:
-    domain: Domein
-    media_block: Mediabestanden weigeren
-    no_domain_blocks: "(geen domeinblokkades)"
-    severity: Zwaarte
-    severity_legend:
-      media_block: Mediabestanden die van deze server komen worden niet opgehaald, opgeslagen en aan de gebruiker getoond.
-      title: Zwaartes
-    show_rationale: Motivering tonen
-    silence: Negeren
+  domain_validator:
+    invalid_domain: is een ongeldige domeinnaam
   errors:
-    '400': The request you submitted was invalid or malformed.
+    '400': De aanvraag die je hebt ingediend was ongeldig of foutief.
     '403': Jij hebt geen toestemming om deze pagina te bekijken.
     '404': De pagina waarnaar jij op zoek bent bestaat niet.
-    '406': This page is not available in the requested format.
+    '406': Deze pagina is niet beschikbaar in het opgevraagde formaat.
     '410': De pagina waarnaar jij op zoek bent bestaat niet meer.
     '422':
       content: Veiligheidsverificatie mislukt. Blokkeer je toevallig cookies?
@@ -630,7 +691,7 @@ nl:
     '500':
       content: Het spijt ons, er is aan onze kant iets fout gegaan.
       title: Er is iets mis
-    '503': The page could not be served due to a temporary server failure.
+    '503': De pagina kon door een tijdelijke serverstoring niet worden geladen.
     noscript_html: Schakel JavaScript in om de webapp van Mastodon te kunnen gebruiken. Als alternatief kan je een <a href="%{apps_path}">Mastodon-app</a> zoeken voor jouw platform.
   existing_username_validator:
     not_found: Kon geen lokale gebruiker met die gebruikersnaam vinden
@@ -654,6 +715,7 @@ nl:
     add_new: Nieuwe toevoegen
     errors:
       limit: Je hebt al het maximaal aantal hashtags uitgelicht
+    hint_html: "<strong>Wat zijn uitgelichte hashtags?</strong> Deze worden prominent op jouw openbare profiel getoond en stelt mensen in staat om jouw openbare toots per hashtag te bekijken. Het zijn een goed hulpmiddel om creatieve werkzaamheden of langetermijnprojecten bij te houden."
   filters:
     contexts:
       home: Starttijdlijn
@@ -679,6 +741,7 @@ nl:
     all: Alles
     changes_saved_msg: Wijzigingen succesvol opgeslagen!
     copy: Kopiëren
+    no_batch_actions_available: Geen batchacties op deze pagina beschikbaar
     order_by: Sorteer op
     save_changes: Wijzigingen opslaan
     validation_errors:
@@ -749,10 +812,32 @@ nl:
       images_and_video: Een video kan niet aan een toot met afbeeldingen worden gekoppeld
       too_many: Er kunnen niet meer dan 4 afbeeldingen toegevoegd worden
   migrations:
-    acct: gebruikersnaam@domein van het nieuwe account
-    currently_redirecting: 'Jouw profiel wordt nu doorverwezen naar:'
-    proceed: Opslaan
-    updated_msg: Jouw accountmigratie-instelling is succesvol bijgewerkt!
+    acct: Verhuisd naar
+    cancel: Doorverwijzing annuleren
+    cancel_explanation: Het annuleren van de doorverwijzing zal jouw huidige account opnieuw activeren, maar brengt geen volgers terug die naar het andere account zijn verhuisd.
+    cancelled_msg: De doorverwijzing is succesvol geannuleerd.
+    errors:
+      already_moved: is hetzelfde account waarnaar je al naar toe bent verhuisd
+      missing_also_known_as: verwijst niet terug naar dit account
+      move_to_self: kan niet het huidige account zijn
+      not_found: kon niet worden gevonden
+      on_cooldown: Jouw laatste migratie is nog te kort geleden
+    followers_count: Volgers op het moment van verhuizing
+    incoming_migrations: Verhuizen vanaf een ander account
+    incoming_migrations_html: Om vanaf een ander account naar dit account te verhuizen, dien je eerst <a href="%{path}">een accountalias aan te maken</a>.
+    moved_msg: Jouw account wordt nu naar %{acct} doorverwezen en jouw volgers worden verhuisd.
+    not_redirecting: Jouw account wordt momenteel niet naar een ander account doorverwezen.
+    on_cooldown: Je hebt recentelijk jouw account verhuisd. Deze mogelijkheid is weer beschikbaar over %{count} dagen.
+    past_migrations: Vorige migraties
+    proceed_with_move: Volgers verhuizen
+    redirecting_to: Jouw account wordt nu naar %{acct} doorverwezen.
+    warning:
+      backreference_required: Het nieuwe account moet eerst worden ingesteld om naar dit account te kunnen terugverwijzen
+      before: 'Lees eerst goed deze tekst, alvorens verder te gaan:'
+      cooldown: Na de verhuizing kun je tijdelijk niet opnieuw verhuizen
+      disabled_account: Jouw huidige account is hierna niet meer volledig bruikbaar. Je hebt echter wel toegang tot het exporteren van je gegevens en tot het opnieuw activeren van je account.
+      followers: Deze actie verhuisd alle volgers vanaf het huidige account naar het nieuwe account
+      other_data: Geen andere gegevens worden automatisch verhuisd
   moderation:
     title: Moderatie
   notification_mailer:
@@ -897,6 +982,7 @@ nl:
   settings:
     account: Account
     account_settings: Accountinstellingen
+    aliases: Accountaliassen
     appearance: Uiterlijk
     authorized_apps: Geautoriseerde apps
     back: Terug naar Mastodon
@@ -914,6 +1000,8 @@ nl:
     profile: Profiel
     relationships: Volgers en gevolgden
     two_factor_authentication: Tweestapsverificatie
+  spam_check:
+    spam_detected_and_silenced: Dit is een automatisch gegenereerde rapportage. Er is spam gedetecteerd en de verzender hiervan werd automatisch genegeerd. Wanneer dit een vergissing is, kun je het negeren van dit account beter weer ongedaan maken.
   statuses:
     attached:
       description: 'Bijlagen: %{attached}'
@@ -955,6 +1043,8 @@ nl:
     pinned: Vastgemaakte toot
     reblogged: boostte
     sensitive_content: Gevoelige inhoud
+  tags:
+    does_not_match_previous_name: komt niet overeen met de vorige naam
   terms:
     body_html: |
       <h2>Privacy Policy</h2>
@@ -1072,7 +1162,9 @@ nl:
         disable: Zolang jouw account is bevroren blijven jouw accountgegevens intact, maar kun je geen handelingen uitvoeren totdat het account is vrijgegeven.
         silence: Zolang jouw account wordt beperkt, kunnen alleen mensen die jou al volgen jouw toots op deze server zien. Tevens ben je niet zichtbaar in meldingen, gesprekken en op openbare tijdlijnen. Anderen kunnen je echter wel handmatig volgen.
         suspend: Jouw account is opgeschort. Jouw toots en geüploade media zijn onomkeerbaar van deze server verwijderd, en ook o.a. van de servers waar jij volgers had.
+      get_in_touch: Je kunt deze e-mail beantwoorden om in contact te komen met de medewerkers van %{instance}.
       review_server_policies: Serverbeleid bekijken
+      statuses: 'Met name voor:'
       subject:
         disable: Jouw account %{acct} is bevroren
         none: Waarschuwing voor %{acct}
diff --git a/config/locales/no.yml b/config/locales/no.yml
index 1d675aef6..c6b9605b3 100644
--- a/config/locales/no.yml
+++ b/config/locales/no.yml
@@ -7,9 +7,6 @@
     contact: Kontakt
     contact_missing: Ikke innstilt
     contact_unavailable: Ikke tilgjengelig
-    extended_description_html: |
-      <h3>En god plassering for regler</h3>
-      <p>En utvidet beskrivelse er ikke satt opp ennå.</p>
     generic_description: "%{domain} er en tjener i nettverket"
     hosted_on: Mastodon driftet på %{domain}
     learn_more: Lær mer
@@ -394,9 +391,6 @@
       too_many: Kan ikke legge ved mer enn 4 filer
   migrations:
     acct: brukernavn@domene til den nye kontoen
-    currently_redirecting: 'Din profil er omdirigert til:'
-    proceed: Lagre
-    updated_msg: Dine innstillinger for kontomigrering er oppdatert!
   moderation:
     title: Moderasjon
   notification_mailer:
diff --git a/config/locales/oc.yml b/config/locales/oc.yml
index 2884380b8..819ea3ef6 100644
--- a/config/locales/oc.yml
+++ b/config/locales/oc.yml
@@ -17,9 +17,6 @@ oc:
     contact_unavailable: Pas disponible
     discover_users: Descobrissètz de nòvas personas
     documentation: Documentacion
-    extended_description_html: |
-      <h3>Una bona plaça per las règlas</h3>
-      <p>La descripcion longa es pas estada causida pel moment.</p>
     federation_hint_html: Amb un compte sus %{instance} poiretz sègre de personas de qualque siasque servidor Mastodon e encara mai.
     generic_description: "%{domain} es un dels servidors del malhum"
     get_apps: Ensajatz una aplicacion mobil
@@ -35,6 +32,9 @@ oc:
     status_count_before: qu’an escrich
     tagline: Seguètz d’amics e trobatz-ne de nòus
     terms: Condicions d’utilizacion
+    unavailable_content: Contengut pas disponible
+    unavailable_content_description:
+      reason: 'Motiu :'
     user_count_after:
       one: utilizaire
       other: utilizaires
@@ -53,6 +53,7 @@ oc:
     media: Mèdias
     moved_html: "%{name} a mudat a %{new_profile_link} :"
     network_hidden: Aquesta informacion es pas disponibla
+    never_active: Jamai
     nothing_here: I a pas res aquí !
     people_followed_by: Lo monde que %{name} sèc
     people_who_follow: Lo monde que sègon %{name}
@@ -219,10 +220,12 @@ oc:
       deleted_status: "(estatut suprimit)"
       title: Audit dels jornals
     custom_emojis:
+      assign_category: Atribuir una categoria
       by_domain: Domeni
       copied_msg: Còpia locala de l’emoji ben creada
       copy: Copiar
       copy_failed_msg: Fracàs de la còpia locala de l’emoji
+      create_new_category: Crear una nòva categoria
       created_msg: Emoji ben creat !
       delete: Suprimir
       destroyed_msg: Emoji ben suprimit !
@@ -230,8 +233,10 @@ oc:
       disabled_msg: Aqueste emoji es ben desactivat
       emoji: Emoji
       enable: Activar
+      enabled: Activat
       enabled_msg: Aqueste emoji es ben activat
       image_hint: PNG cap a 50Ko
+      list: Listar
       listed: Listat
       new:
         title: Ajustar un nòu emoji personal
@@ -239,11 +244,14 @@ oc:
       shortcode: Acorchi
       shortcode_hint: Almens 2 caractèrs, solament alfanumerics e jonhent bas
       title: Emojis personals
+      uncategorized: Sens categoria
+      unlist: Listar pas
       unlisted: Pas listat
       update_failed_msg: Mesa a jorn de l’emoji fracasada
       updated_msg: Emoji ben mes a jorn !
       upload: Enviar
     dashboard:
+      authorized_fetch_mode: Mòde recuperacion autorizat
       backlog: Accions en retard
       config: Configuracion
       feature_deletions: Supressions de comptes
@@ -256,6 +264,8 @@ oc:
       features: Foncionalitats
       hidden_service: Federacion amb servicis amagats
       open_reports: Senhalaments dobèrts
+      pending_tags: etiquetas en espèra de validacion
+      pending_users: utilizaires en espèra de validacion
       recent_users: Utilizaires recents
       search: Recèrca tèxte complèt
       single_user_mode: Mòde sol utilizaire
@@ -290,6 +300,7 @@ oc:
           suspend: Suspendre
         title: Nòu blocatge domeni
       private_comment: Comentari privat
+      private_comment_hint: Comentari tocant la limitacion d’aqueste domeni per un usatge intèrn pels moderators.
       public_comment: Comentari public
       reject_media: Regetar los fichièrs mèdias
       reject_media_hint: Lèva los fichièrs gardats localament e regèta las demandas de telecargament dins lo futur. Servís pas a res per las suspensions
@@ -365,6 +376,7 @@ oc:
       pending: En espèra d’aprovacion del relai
       save_and_enable: Salvar e activar
       setup: Configurar una connexion relai
+      signatures_not_enabled: Los relais foncionaràn pas coma cal se lo mòde segur o lista blanca es activat
       status: Estatut
       title: Relais
     report_notes:
@@ -413,6 +425,15 @@ oc:
       custom_css:
         desc_html: Modificar l’estil amb una fuèlha CSS cargada sus cada pagina
         title: CSS personalizada
+      default_noindex:
+        desc_html: Tòca totes los utilizaires qu’an pas cambiat lo paramètre
+      domain_blocks:
+        all: A tot lo monde
+        disabled: A degun
+        title: Mostrar los blocatges de domeni
+        users: Als utilizaires locals connectats
+      domain_blocks_rationale:
+        title: Mostrar lo rasonament
       hero:
         desc_html: Mostrat en primièra pagina. Almens 600x100px recomandat. S’es pas configurat l’imatge del servidor serà mostrat
         title: Imatge de l’eròi
@@ -472,12 +493,15 @@ oc:
         desc_html: Mostrar lo flux public sus la pagina d’acuèlh
         title: Apercebut flux public
       title: Paramètres del site
+      trends:
+        title: Etiquetas tendéncia
     statuses:
       back_to_account: Tornar a la pagina Compte
       batch:
         delete: Suprimir
         nsfw_off: Marcar coma pas sensible
         nsfw_on: Marcar coma sensible
+      deleted: Suprimits
       failed_to_execute: Fracàs
       media:
         title: Mèdia
@@ -486,10 +510,22 @@ oc:
       title: Estatuts del compte
       with_media: Amb mèdia
     tags:
+      accounts_today: Utilizacions unicas uèi
+      accounts_week: Utilizacions unicas aquesta setmana
       context: Contèxt
       directory: A l’annuari
       in_directory: "%{count} a l’annuari"
+      last_active: Darrièra activitat
+      most_popular: Mai popularas
+      most_recent: Mai recentas
+      name: Etiqueta
+      review: Repassar l’estatut
+      reviewed: Repassadas
       title: Etiquetas
+      trending_right_now: Actualament en tendéncia
+      unique_uses_today: "%{count} publicacions uèi"
+      unreviewed: Pas repassadas
+      updated_msg: Paramètres d’etiquetas corrèctament actualizats
     title: Administracion
     warning_presets:
       add_new: N’ajustar un nòu
@@ -510,6 +546,7 @@ oc:
     advanced_web_interface_hint: 'Se volètz utilizar la nautor complèta de l’ecran, l’interfàcia web avançada vos permet de configurar diferentas colomnas per mostrar tan d’informacions que volètz : Acuèlh, notificacions, flux d’actualitat, e d’autras listas e etiquetas.'
     animations_and_accessibility: Animacion e accessibilitat
     confirmation_dialogs: Fenèstras de confirmacion
+    discovery: Descobèrta
     sensitive_content: Contengut sensible
   application_mailer:
     notification_preferences: Cambiar las preferéncias de corrièl
@@ -530,8 +567,12 @@ oc:
     apply_for_account: Demandar una invitacion
     change_password: Senhal
     checkbox_agreement_html: Accepti las <a href="%{rules_path}" target="_blank">règlas del servidor</a> e <a href="%{terms_path}" target="_blank">los tèrmes del servici</a>
+    checkbox_agreement_without_rules_html: Soi d’acòrdi amb las <a href="%{terms_path}" target="_blank">condicions d’utilizacion</a>
     delete_account: Suprimir lo compte
     delete_account_html: Se volètz suprimir vòstre compte, podètz <a href="%{path}">o far aquí</a>. Vos demandarem que confirmetz.
+    description:
+      prefix_invited_by_user: "@%{name} vos convida a rejónher aqueste servidor Mastodon !"
+      prefix_sign_up: Marcatz-vos a Mostodon uèi !
     didnt_get_confirmation: Avètz pas recebut las instruccions de confirmacion ?
     forgot_password: Senhal oblidat ?
     invalid_reset_password_token: Lo geton de reïnicializacion es invalid o acabat. Tornatz demandar un geton se vos plai.
@@ -553,6 +594,7 @@ oc:
       title: Configuracion
     status:
       account_status: Estat del compte
+      functional: Vòstre compte es complètament foncional.
     trouble_logging_in: Problèmas de connexion ?
   authorize_follow:
     already_following: Seguètz ja aqueste compte
@@ -565,6 +607,11 @@ oc:
       return: Veire lo perfil a la persona
       web: Tornar a l’interfàcia Web
     title: Sègre %{acct}
+  challenge:
+    confirm: Contunhar
+    hint_html: "<strong>Asutúcia :</strong> vos demandarem pas vòstre senhal de nòu d’aquí unas oras."
+    invalid_password: Senhal invalid
+    prompt: Confirmatz lo senhal per dire de contunhar
   datetime:
     distance_in_words:
       about_x_hours: "%{count} h"
@@ -580,18 +627,29 @@ oc:
       x_months: "%{count} meses"
       x_seconds: "%{count}s"
   deletes:
+    challenge_not_passed: Las informacions qu’avètz fornidas son pas corrèctas
     confirm_password: Picatz vòstre senhal actual per verificar vòstra identitat
+    confirm_username: Picatz vòstre nom d’utilizaire per confirmar la procedura
     proceed: Suprimir lo compte
     success_msg: Compte ben suprimit
+    warning:
+      caches: Lo contengut en cache suls autres servidors pòt demorar
+      email_change_html: Podètz <a href="%{path}">cambiar vòstra adreça electronia</a>sens suprimir vòstre compte
+      irreversible: Poiretz pas restaurar o reactivar vòstre compte
+      more_details_html: Per mai d’informacion, vejatz la <a href="%{terms_path}">politica de confidencialitat</a>.
+      username_available: Vòstre nom d’utilizaire serà disponible de nòu
+      username_unavailable: Vòstre nom d’utilizaire demorarà pas disponible
   directories:
     directory: Annuari de perfils
     explanation: Trobar d’utilizaires segon lor interèsses
     explore_mastodon: Explorar %{title}
+  domain_validator:
+    invalid_domain: es pas un nom de domeni valid
   errors:
     '400': The request you submitted was invalid or malformed.
     '403': Avètz pas l’autorizacion de veire aquesta pagina.
     '404': La pagina que cercatz existís pas aquí.
-    '406': This page is not available in the requested format.
+    '406': La pagina es pas disponibla dins lo format demandat.
     '410': La pagina que cercatz existís pas mai aquí.
     '422':
       content: Verificacion de seguretat fracassada. Blocatz los cookies ?
@@ -644,10 +702,12 @@ oc:
     developers: Desvolopaires
     more: Mai…
     resources: Ressorsas
+    trending_now: Tendéncia del moment
   generic:
     all: Tot
     changes_saved_msg: Cambiaments ben realizats !
     copy: Copiar
+    no_batch_actions_available: Cap d’accion de massa pas disponibla sus aquesta pagina
     order_by: Triar per
     save_changes: Salvar los cambiaments
     validation_errors:
@@ -719,9 +779,20 @@ oc:
       too_many: Se pòt pas ajustar mai de 4 fichièrs
   migrations:
     acct: nomutilizaire@domeni del nòu compte
-    currently_redirecting: 'Vòstre perfil es parametrat per mandar a :'
-    proceed: Enregistrar
-    updated_msg: Vòstre paramètre de migracion es ben estat mes a jorn !
+    cancel: Anullar la redireccion
+    cancelled_msg: Redireccion corrèctament anullada.
+    errors:
+      move_to_self: pòt pas èsser lo compte actual
+      not_found: impossible de trobar
+    incoming_migrations: Mudar d’un compte diferent
+    moved_msg: Vòstre compte manda ara a %{acct} e vòstres seguidors son desplaçats.
+    not_redirecting: Vòstre compte manda pas enlòc pel moment.
+    past_migrations: Migracions passadas
+    proceed_with_move: Desplaçar los seguidors
+    redirecting_to: Vòstre compte manda a %{acct}.
+    warning:
+      before: 'Abans de contunhar, volgatz legir aquestas nòtas amb atencion :'
+      other_data: Cap d’autra donada serà desplaçada automaticament
   moderation:
     title: Moderacion
   notification_mailer:
@@ -924,6 +995,8 @@ oc:
     pinned: Tut penjat
     reblogged: a partejat
     sensitive_content: Contengut sensible
+  tags:
+    does_not_match_previous_name: correspond pas al nom precedent
   terms:
     body_html: |
       <h2>Politica de confidencialitat</h2>
@@ -1043,7 +1116,9 @@ oc:
         disable: Quand vòstre compte es gelat, las donadas d’aqueste demòran senceras, mas podètz pas realizar cap d’accion fins que siá desblocat.
         silence: Del temps que vòstre compte es limitat, solament lo monde que vos sègon veiràn vòstres tuts sus aqueste servidor, e poiriatz èsser tirat de mantunas listas publicas. Pasmens, d’autres vos pòdon sègre manualament.
         suspend: Vòstre compte es suspendut e totes vòstres tuts e fichièrs enviats son estats suprimits sens retorn possible d’aqueste servidor e los de vòstres seguidors.
+      get_in_touch: Podètz respondre a aqueste corrièl per contactar la còla de %{instance}.
       review_server_policies: Repassar las politicas del servidor
+      statuses: 'Especificament per :'
       subject:
         disable: Vòstre compte %{acct} es gelat
         none: Avertiment per %{acct}
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 8b32e6d22..af3a55211 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -17,9 +17,6 @@ pl:
     contact_unavailable: Nie dotyczy
     discover_users: Odkrywaj użytkowników
     documentation: Dokumentacja
-    extended_description_html: |
-      <h3>Dobre miejsce na zasady użytkowania</h3>
-      <p>Nie ustawiono jeszcze szczegółowego opisu</p>
     federation_hint_html: Z kontem na %{instance}, możesz śledzić użytkowników każdego serwera Mastodona i nie tylko.
     generic_description: "%{domain} jest jednym z serwerów sieci"
     get_apps: Spróbuj aplikacji mobilnej
@@ -713,9 +710,6 @@ pl:
       too_many: Nie możesz załączyć więcej niż 4 plików
   migrations:
     acct: nazwa@domena nowego konta
-    currently_redirecting: 'Obecnie Twoje konto przekierowuje do:'
-    proceed: Zapisz
-    updated_msg: Pomyślnie zaktualizowano ustawienia migracji Twojego konta!
   moderation:
     title: Moderacja
   notification_mailer:
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 9896f888a..32ea8caf6 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -7,6 +7,7 @@ pt-BR:
     active_count_after: Ativo
     active_footnote: Usuários ativos mensais (UAM)
     administered_by: 'Administrado por:'
+    api: API
     apps: Apps
     apps_platforms: Use o Mastodon a partir de iOS, Android e outras plataformas
     browse_directory: Navegue pelo diretório de perfis e filtre por interesses
@@ -16,9 +17,6 @@ pt-BR:
     contact_unavailable: Não disponível
     discover_users: Descubra usuários
     documentation: Documentação
-    extended_description_html: |
-      <h3>Um bom lugar para regras</h3>
-      <p>A descrição da instância ainda não foi feita.</p>
     federation_hint_html: Com uma conta em %{instance} você vai poder seguir pessoas em qualquer servidor Mastodon ou outros do fediverso.
     generic_description: "%{domain} é um servidor na rede"
     get_apps: Experimente um aplicativo
@@ -31,6 +29,11 @@ pt-BR:
     status_count_before: Autores de
     tagline: Siga amigos e encontre novos
     terms: Termos de serviço
+    unavailable_content: Conteúdo indisponível
+    unavailable_content_description:
+      reason: 'Motivo:'
+      suspended: Você não será capaz de seguir ninguém deste servidor, e nenhum dado dele será processado ou armazenado, e nenhum dado trocado.
+    unavailable_content_html: Mastodon geralmente permite que você veja o conteúdo e interaja com usuários de qualquer outro servidor no fediverso. Estas são as exceções deste servidor específico.
     user_count_after:
       one: usuário
       other: usuários
@@ -38,6 +41,7 @@ pt-BR:
     what_is_mastodon: O que é Mastodon?
   accounts:
     choices_html: 'Escolhas de %{name}:'
+    featured_tags_hint: Você pode destacar hashtags específicas que serão exibidas aqui.
     follow: Seguir
     followers:
       one: Seguidor
@@ -49,11 +53,16 @@ pt-BR:
     media: Mídia
     moved_html: "%{name} se mudou para %{new_profile_link}:"
     network_hidden: Esta informação não está disponível
+    never_active: Nunca
     nothing_here: Não há nada aqui!
     people_followed_by: Pessoas que %{name} segue
     people_who_follow: Pessoas que seguem %{name}
     pin_errors:
       following: Você tem que estar seguindo a pessoa que você quer sugerir
+    posts:
+      one: Toot
+      other: Toots
+    posts_tab_heading: Toots
     posts_with_replies: Toots e respostas
     reserved_username: Este usuário está reservado
     roles:
@@ -75,6 +84,7 @@ pt-BR:
       approve: Aprovar
       approve_all: Aprovar tudo
       are_you_sure: Você tem certeza?
+      avatar: Imagem de Perfil
       by_domain: Domínio
       change_email:
         changed_msg: E-mail da conta modificado com sucesso!
@@ -105,9 +115,11 @@ pt-BR:
       header: Cabeçalho
       inbox_url: URL da caixa de entrada
       invited_by: Convidado por
+      ip: IP
       joined: Se cadastrou
       location:
         all: Todos
+        local: Local
         remote: Remoto
         title: Localização
       login_status: Situação de login
@@ -163,6 +175,7 @@ pt-BR:
       statuses: Postagens
       subscribe: Inscrever-se
       suspended: Suspenso
+      time_in_queue: Esperando na fila por %{time}
       title: Contas
       unconfirmed_email: E-mail não confirmado
       undo_silenced: Retirar silenciamento
@@ -170,6 +183,7 @@ pt-BR:
       unsubscribe: Desinscrever-se
       username: Nome de usuário
       warn: Notificar
+      web: Web
     action_logs:
       actions:
         assigned_to_self_report: "%{name} designou a denúncia %{target} para si"
@@ -205,15 +219,18 @@ pt-BR:
       deleted_status: "(status deletado)"
       title: Auditar relatório
     custom_emojis:
+      assign_category: Designar Categoria
       by_domain: Domínio
       copied_msg: Cópia local do emoji criada com sucesso
       copy: Copiar
       copy_failed_msg: Não foi possível criar uma cópia local deste emoji
+      create_new_category: Criar nova categoria
       created_msg: Emoji criado com sucesso!
       delete: Excluir
       destroyed_msg: Emoji deletado com sucesso!
       disable: Desabilitar
       disabled_msg: Emoji desabilitado com sucesso
+      emoji: Emoji
       enable: Habilitar
       enabled_msg: Emoji habilitado com sucesso
       image_hint: PNG de até 50KB
@@ -224,6 +241,7 @@ pt-BR:
       shortcode: Atalho
       shortcode_hint: Pelo menos 2 caracteres, apenas caracteres alfanuméricos e underscores
       title: Emojis customizados
+      uncategorized: Não categorizado
       unlisted: Não listado
       update_failed_msg: Não foi possível atualizar esse emoji
       updated_msg: Emoji atualizado com sucesso!
@@ -236,13 +254,17 @@ pt-BR:
       feature_profile_directory: Diretório de perfis
       feature_registrations: Cadastros
       feature_relay: Repetidor da federação
+      feature_spam_check: Anti-spam
       feature_timeline_preview: pré-visualização da timeline
       features: Funcionalidades
       hidden_service: Federação com serviços onion
       open_reports: Denúncias em aberto
+      pending_tags: hashtags aguardando revisão
+      pending_users: usuários aguardando revisão
       recent_users: Usuários recentes
       search: Pesquisa em texto
       single_user_mode: Modo de usuário único
+      software: Software
       space: Uso de espaço em disco
       title: Painel de controle
       total_users: usuários no total
@@ -255,6 +277,8 @@ pt-BR:
       created_msg: Bloqueio de domínio está sendo processado
       destroyed_msg: Bloqueio de domínio desfeito
       domain: Domínio
+      edit: Editar bloqueio de domínio
+      existing_domain_block_html: Você já impôs limites mais restritivos a %{name}, é necessário primeiro <a href="%{unblock_url}">desbloqueá-lo</a>.
       new:
         create: Criar bloqueio
         hint: O bloqueio de domínio não prevenirá a criação de entradas de contas na base de dados, mas vai reatroativa e automaticamente aplicar métodos específicos de moderação nestas contas.
@@ -264,6 +288,8 @@ pt-BR:
           silence: Silêncio
           suspend: Suspensão
         title: Novo bloqueio de domínio
+      private_comment: Comentário privado
+      public_comment: Comentário público
       reject_media: Rejeitar arquivos de mídia
       reject_media_hint: Remove arquivos de mídia armazenados localmente e recusa quaisquer outros no futuro. Irrelevante para suspensões
       reject_reports: Rejeitar denúncias
@@ -283,6 +309,7 @@ pt-BR:
         title: Retirar bloqueio de domínio de %{domain}
         undo: Retirar
       undo: Retirar bloqueio de domínio
+      view: Ver domínios bloqueados
     email_domain_blocks:
       add_new: Adicionar novo
       created_msg: Bloqueio de domínio de e-mail criado com sucesso
@@ -306,6 +333,8 @@ pt-BR:
         all: Todas
         limited: Limitado
         title: Moderação
+      private_comment: Comentário privado
+      public_comment: Comentário público
       title: Federação
       total_blocked_by_us: Bloqueado por nós
       total_followed_by_them: Seguidos por eles
@@ -381,6 +410,15 @@ pt-BR:
       custom_css:
         desc_html: Modificar o visual com CSS que é carregado em todas as páginas
         title: CSS customizado
+      default_noindex:
+        desc_html: Afeta qualquer usuário que não tenha modificado esta configuração manualmente
+      domain_blocks:
+        all: Para todo mundo
+        disabled: Para ninguém
+        title: Mostrar domínios bloqueados
+        users: Para usuários locais logados
+      domain_blocks_rationale:
+        title: Visualizar justificativa
       hero:
         desc_html: Aparece na página inicial. Ao menos 600x100px é recomendado. Se não estiver definido, o thumbnail da instância é usado no lugar
         title: Imagem de capa
@@ -431,6 +469,8 @@ pt-BR:
         desc_html: Você pode escrever a sua própria política de privacidade, termos de serviço, entre outras coisas. Você pode usar tags HTML
         title: Termos de serviço customizados
       site_title: Nome da instância
+      spam_check_enabled:
+        title: Automação anti-spam
       thumbnail:
         desc_html: Usada para prévias via OpenGraph e API. Recomenda-se 1200x630px
         title: Miniatura da instância
@@ -438,12 +478,15 @@ pt-BR:
         desc_html: Exibir a timeline pública na página inicial
         title: Prévia da timeline
       title: Configurações do site
+      trends:
+        title: Hashtags em alta
     statuses:
       back_to_account: Voltar para página da conta
       batch:
         delete: Deletar
         nsfw_off: Marcar como não-sensível
         nsfw_on: Marcar como sensível
+      deleted: Excluídos
       failed_to_execute: Falha em executar
       media:
         title: Mídia
@@ -451,6 +494,16 @@ pt-BR:
       no_status_selected: Nenhum status foi modificado porque nenhum estava selecionado
       title: Postagens da conta
       with_media: Com mídia
+    tags:
+      context: Contexto
+      directory: No diretório
+      most_popular: Mais populares
+      most_recent: Mais recentes
+      name: Hashtag
+      title: Hashtags
+      trending_right_now: Em alta no momento
+      unreviewed: Não revisadas
+      updated_msg: Configurações de hashtag atualizadas com sucesso
     title: Administração
     warning_presets:
       add_new: Adicionar um novo
@@ -466,8 +519,14 @@ pt-BR:
       body: "%{reporter} denunciou %{target}"
       body_remote: Alguém da instância %{domain} reportou %{target}
       subject: Nova denúncia sobre %{instance} (#%{id})
+  appearance:
+    animations_and_accessibility: Animações e acessibilidade
+    confirmation_dialogs: Popups de confirmação
+    discovery: Descobrir
+    sensitive_content: Conteúdo sensível
   application_mailer:
     notification_preferences: Mudar preferências de e-mail
+    salutation: "%{name},"
     settings: 'Mudar e-mail de preferência: %{link}'
     view: 'Visualizar:'
     view_profile: Ver perfil
@@ -484,8 +543,13 @@ pt-BR:
     apply_for_account: Pedir um convite
     change_password: Senha
     checkbox_agreement_html: Eu concordo com <a href="%{rules_path}" target="_blank">as regras do servidor</a> e com <a href="%{terms_path}" target="_blank">os termos de serviço</a>
+    checkbox_agreement_without_rules_html: Concordo com os <a href="%{terms_path}" target="_blank">termos do serviço </a>
     delete_account: Excluir conta
     delete_account_html: Se você deseja excluir a sua conta, você pode <a href="%{path}">prosseguir para cá</a>. Uma confirmação será requisitada.
+    description:
+      prefix_invited_by_user: "@%{name} convidou você para entrar neste servidor do Mastodon!"
+      prefix_sign_up: Cadastre-se no Mastodon hoje!
+      suffix: Com uma conta, você poderá seguir pessoas, postar atualizações, trocar mensagens com usuários de qualquer servidor Mastodon e muito mais!
     didnt_get_confirmation: Não recebeu instruções de confirmação?
     forgot_password: Esqueceu a sua senha?
     invalid_reset_password_token: Token de modificação de senha é inválido ou expirou. Por favor, requisite um novo.
@@ -494,6 +558,9 @@ pt-BR:
     migrate_account: Mudar para uma conta diferente
     migrate_account_html: Se você quer redirecionar essa conta para uma outra você pode <a href="%{path}">configurar isso aqui</a>.
     or_log_in_with: Ou faça login com
+    providers:
+      cas: CAS
+      saml: SAML
     register: Cadastrar-se
     registration_closed: "%{instance} não está aceitando novos membros"
     resend_confirmation: Reenviar instruções de confirmação
@@ -512,8 +579,12 @@ pt-BR:
       return: Exibir o perfil do usuário
       web: Voltar para a página inicial
     title: Seguir %{acct}
+  challenge:
+    invalid_password: Senha inválida
+    prompt: Confirme sua senha para continuar
   datetime:
     distance_in_words:
+      about_x_hours: "%{count}h"
       about_x_months: "%{count} meses"
       about_x_years: "%{count} anos"
       almost_x_years: "%{count} anos"
@@ -526,9 +597,16 @@ pt-BR:
       x_months: "%{count} meses"
       x_seconds: "%{count} segundos"
   deletes:
+    challenge_not_passed: As informações que você inseriu não estão corretas
     confirm_password: Insira a sua senha atual para verificar a sua identidade
+    confirm_username: Digite seu nome de usuário para confirmar o procedimento
     proceed: Excluir conta
     success_msg: A sua conta foi excluída com sucesso
+    warning:
+      before: 'Antes de prosseguir, por favor leia com cuidado:'
+      data_removal: Suas postagens e outros dados serão removidos permanentemente
+      username_available: Seu nome de usuário ficará disponível novamente
+      username_unavailable: Seu nome de usuário permanecerá indisponível
   directories:
     directory: Diretório de perfis
     explanation: Descobrir usuários baseado em seus interesses
@@ -560,6 +638,7 @@ pt-BR:
       request: Solicitar o seu arquivo
       size: Tamanho
     blocks: Você bloqueou
+    csv: CSV
     domain_blocks: Bloqueios de domínio
     follows: Você segue
     lists: Listas
@@ -664,9 +743,15 @@ pt-BR:
       too_many: Não é possível anexar mais de 4 imagens
   migrations:
     acct: username@domain da nova conta
-    currently_redirecting: 'Seu perfil está configurado para redirecionar para:'
-    proceed: Salvar
-    updated_msg: As configurações de migração da sua conta foram atualizadas com sucesso!
+    incoming_migrations: Migrando de outra conta
+    moved_msg: Agora sua conta está redirecionando para %{acct} e seus seguidores estão sendo movidos.
+    not_redirecting: Sua conta não está redirecionando para nenhuma outra conta atualmente.
+    on_cooldown: Você migrou recentemente sua conta. Esta função ficará disponível novamente em %{count} dias.
+    past_migrations: Migrações passadas
+    proceed_with_move: Migrar seguidores
+    redirecting_to: Sua conta está redirecionando para %{acct}.
+    warning:
+      before: 'Antes de prosseguir, por favor leia com cuidado:'
   moderation:
     title: Moderação
   notification_mailer:
@@ -758,13 +843,40 @@ pt-BR:
     activity: Última atividade
     browser: Navegador
     browsers:
+      alipay: Alipay
+      blackberry: BlackBerry
+      chrome: Chrome
+      edge: Microsoft Edge
+      electron: Electron
+      firefox: Firefox
       generic: Navegador desconhecido
+      ie: Internet Explorer
+      micro_messenger: MicroMessenger
       nokia: Navegador Nokia S40 Ovi
+      opera: Opera
+      otter: Otter
+      phantom_js: PhantomJS
+      qq: QQ Browser
+      safari: Safari
+      uc_browser: UCBrowser
+      weibo: Weibo
     current_session: Sessão atual
     description: "%{browser} em %{platform}"
     explanation: Estes são os navegadores que estão conectados com a sua conta do Mastodon.
+    ip: IP
     platforms:
+      adobe_air: Adobe Air
+      android: Android
+      blackberry: BlackBerry
+      chrome_os: ChromeOS
+      firefox_os: Firefox OS
+      ios: iOS
+      linux: Linux
+      mac: Mac
       other: Plataforma desconhecida
+      windows: Windows
+      windows_mobile: Windows Mobile
+      windows_phone: Windows Phone
     revoke: Revogar
     revoke_success: Sessão revogada com sucesso
     title: Sessões
@@ -788,6 +900,8 @@ pt-BR:
     profile: Perfil
     relationships: Seguindo e seguidores
     two_factor_authentication: Autenticação em dois passos
+  spam_check:
+    spam_detected_and_silenced: Este é um relatório automatizado. Spam foi detectado e o remetente foi silenciado automaticamente. Se isto for um erro, por favor, desfaça esta ação.
   statuses:
     attached:
       description: 'Anexado: %{attached}'
@@ -817,6 +931,7 @@ pt-BR:
       vote: Votar
     show_more: Mostrar mais
     sign_in_to_participate: Entre para participar dessa conversa
+    title: '%{name}: "%{quote}"'
     visibilities:
       private: Apenas seguidores
       private_long: Mostrar apenas para seguidores
@@ -828,6 +943,8 @@ pt-BR:
     pinned: Toot fixado
     reblogged: compartilhou
     sensitive_content: Conteúdo sensível
+  tags:
+    does_not_match_previous_name: não corresponde ao nome anterior
   terms:
     body_html: |
       <h2>Política de privacidade</h2>
@@ -944,6 +1061,7 @@ pt-BR:
         disable: Enquanto sua conta está congelada, seus dados estão intactos, mas você não pode realizar nenhuma ação até que sua conta seja desbloqueada.
         silence: Enquanto sua conta está limitada, somente pessoas que já estão seguindo você poderão ver seus toots nesse servidor, e você pode ser excluído de diversas listagens públicas. No entanto, outros ainda podem seguir você manualmente.
         suspend: Sua conta está suspensa e todos os seus toots e mídias foram irreversivelmente removidas desse servidor e de servidores onde você tinha seguidores.
+      get_in_touch: Você pode responder a este e-mail para entrar em contato com a equipe de %{instance}.
       review_server_policies: Revisar as políticas do servidor
       subject:
         disable: Sua conta %{acct} foi congelada
diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml
index 25ee57085..ecca3b845 100644
--- a/config/locales/pt-PT.yml
+++ b/config/locales/pt-PT.yml
@@ -10,9 +10,6 @@ pt-PT:
     contact_missing: Não configurado
     contact_unavailable: n.d.
     documentation: Documentação
-    extended_description_html: |
-      <h3>Um bom lugar para regras</h3>
-      <p>A descrição estendida ainda não foi configurada.</p>
     generic_description: "%{domain} é um servidor na rede"
     hosted_on: Mastodon em %{domain}
     learn_more: Saber mais
@@ -612,9 +609,6 @@ pt-PT:
       too_many: Não é possível anexar mais de 4 arquivos
   migrations:
     acct: username@domain da nova conta
-    currently_redirecting: 'O teu perfil está configurado para redirecionar para:'
-    proceed: Salvar
-    updated_msg: As configurações de migração da tua conta foram atualizadas com sucesso!
   moderation:
     title: Moderação
   notification_mailer:
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 0c1202118..3b10925ac 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -17,9 +17,6 @@ ru:
     contact_unavailable: неизв.
     discover_users: Находите пользователей
     documentation: Документация
-    extended_description_html: |
-      <h3>Хорошее место для правил</h3>
-      <p>Расширенное описание еще не настроено.</p>
     federation_hint_html: С учётной записью на %{instance} вы сможете подписываться на людей с любого сервера Mastodon и не только.
     generic_description: "%{domain} - один из серверов сети"
     get_apps: Попробуйте мобильное приложение
@@ -592,8 +589,6 @@ ru:
     directory: Каталог профилей
     explanation: Находите пользователей по интересам
     explore_mastodon: Изучайте %{title}
-  domain_blocks:
-    domain: Домен
   errors:
     '400': The request you submitted was invalid or malformed.
     '403': У Вас нет доступа к просмотру этой страницы.
@@ -730,9 +725,6 @@ ru:
       too_many: Нельзя добавить более 4 файлов
   migrations:
     acct: имя@домен нового аккаунта
-    currently_redirecting: 'Ваш профиль будет перенаправлен на:'
-    proceed: Сохранить
-    updated_msg: Настройки миграции вашего аккаунта обновлены!
   moderation:
     title: Модерация
   notification_mailer:
diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml
index e09f92205..548d275ba 100644
--- a/config/locales/simple_form.ar.yml
+++ b/config/locales/simple_form.ar.yml
@@ -15,7 +15,7 @@ ar:
         context: واحد أو أكثر من السياقات التي يجب أن ينطبق عليها عامل التصفية
         digest: تُرسَل إليك بعد مُضيّ مدة مِن خمول نشاطك و فقط إذا ما تلقيت رسائل شخصية مباشِرة أثناء فترة غيابك مِن الشبكة
         email: سوف تتلقى رسالة إلكترونية للتأكيد
-        fields: يُمكنك عرض 4 عناصر على شكل جدول في ملفك الشخصي
+        fields: يُمكنك عرض 4 عناصر على شكل جدول في صفحتك التعريفية
         header: ملف PNG أو GIF أو JPG. حجمه على أقصى تصدير %{size}. سيتم تصغيره إلى %{dimensions}px
         inbox_url: نسخ العنوان الذي تريد استخدامه مِن صفحة الاستقبال للمُرحَّل
         irreversible: التبويقات التي تم تصفيتها ستختفي لا محالة حتى و إن تمت إزالة عامِل التصفية لاحقًا
@@ -28,11 +28,13 @@ ar:
         setting_display_media_default: إخفاء الوسائط المُعيَّنة كحساسة
         setting_display_media_hide_all: إخفاء كافة الوسائط دائمًا
         setting_display_media_show_all: دائمًا عرض الوسائط المُعيَّنة كحساسة
-        setting_hide_network: الحسابات التي تُتابعها و التي تُتابِعك على حد سواء لن تُعرَض على صفحتك الشخصية
-        setting_noindex: ذلك يؤثر على حالة ملفك الشخصي و صفحاتك
+        setting_hide_network: الحسابات التي تُتابعها و التي تُتابِعك على حد سواء لن تُعرَض على صفحتك التعريفية
+        setting_noindex: ذلك يؤثر على صفحتك التعريفية وصفحات المنشورات
         username: اسم المستخدم الخاص بك سوف يكون فريدا مِن نوعه على %{domain}
       featured_tag:
-        name: 'رُبَّما تريد/ي استخدام أحد هؤلاء:'
+        name: 'رُبَّما تريد·ين استخدام واحد مِن هذه:'
+      form_challenge:
+        current_password: إنك بصدد الدخول إلى منطقة آمنة
       imports:
         data: ملف CSV تم تصديره مِن خادوم ماستدون آخر
       invite_request:
@@ -46,6 +48,8 @@ ar:
         fields:
           name: التسمية
           value: المحتوى
+      account_alias:
+        acct: مُعرّف الحساب القديم
       account_warning_preset:
         text: نموذج نصي
       admin_account_action:
@@ -72,7 +76,7 @@ ar:
         display_name: الاسم المعروض
         email: عنوان البريد الإلكتروني
         expires_in: تنتهي مدة صلاحيته بعد
-        fields: البيانات الوصفية للصفحة الشخصية
+        fields: البيانات الوصفية للصفحة التعريفية
         header: الرأسية
         inbox_url: عنوان رابط صندوق المُرَحِّل
         irreversible: إسقاط بدلا من إخفائها
@@ -128,6 +132,7 @@ ar:
         reblog: ابعث بريداً إلكترونيًا عندما يقوم أحدهم بترقية منشورك
         report: إرسال رسالة إلكترونية عند تلقّي إبلاغ جديد
       tag:
+        listable: اسمح لهذا الوسم بالظهور في البحث وفي دليل الصفحات التعريفية
         name: الوسم
         usable: اسمح للتبويقات باستخدام هذا الوسم
     'no': لا
diff --git a/config/locales/simple_form.co.yml b/config/locales/simple_form.co.yml
index eeb5a913a..245bcea08 100644
--- a/config/locales/simple_form.co.yml
+++ b/config/locales/simple_form.co.yml
@@ -2,6 +2,10 @@
 co:
   simple_form:
     hints:
+      account_alias:
+        acct: Entrate u cugnome@duminiu di u contu attuale
+      account_migration:
+        acct: Entrate u cugnome@duminiu di u contu induve vulete traslucà
       account_warning_preset:
         text: Pudete utilizà a sintassa di i statuti, per esempiu l'URL, hashtag, minzione
       admin_account_action:
@@ -15,6 +19,8 @@ co:
         avatar: Furmatu PNG, GIF o JPG. %{size} o menu. Sarà ridottu à %{dimensions}px
         bot: Stu contu hè autumatizatu è ùn hè forse micca survegliatu
         context: Cuntestu·i induve u filtru deve esse applicatu
+        current_password: Per ragione di sicurità, entrate a chjave d'accessu di stu contu
+        current_username: Per cunfirmà, entrate u cugnome di questu contu
         digest: Solu mandatu dopu à una longa perioda d’inattività, è solu s’elli ci sò novi missaghji diretti
         discoverable: L'annuariu di i prufili hè un'altra manera per u vostru contu di tuccà un'audienza più larga
         email: Avete da riceve un'e-mail di cunfirmazione
@@ -43,6 +49,8 @@ co:
         domain: Stu duminiu puderà ricuperà i dati di stu servore è i dati ch'affaccanu da quallà saranu trattati è cunservati
       featured_tag:
         name: 'Pudete vulè utilizà unu di quelli:'
+      form_challenge:
+        current_password: Entrate in in una zona sicurizata
       imports:
         data: Un fugliale CSV da un’altru servore di Mastodon
       invite_request:
@@ -58,6 +66,10 @@ co:
         fields:
           name: Marcu
           value: Cuntinutu
+      account_alias:
+        acct: Cugnome di l'anzianu contu
+      account_migration:
+        acct: Cugnome di u novu contu
       account_warning_preset:
         text: Testu preselezziunatu
       admin_account_action:
@@ -131,6 +143,8 @@ co:
         must_be_follower: Piattà e nutificazione di quelli·e ch’ùn vi seguitanu
         must_be_following: Piattà e nutificazione di quelli·e ch’ùn seguitate
         must_be_following_dm: Bluccà e missaghji diretti di quelli·e ch’ùn seguitate
+      invite:
+        comment: Cummentariu
       invite_request:
         text: Perchè vulete ghjunghje?
       notification_emails:
diff --git a/config/locales/simple_form.cs.yml b/config/locales/simple_form.cs.yml
index b6b61747f..047d59c69 100644
--- a/config/locales/simple_form.cs.yml
+++ b/config/locales/simple_form.cs.yml
@@ -2,6 +2,10 @@
 cs:
   simple_form:
     hints:
+      account_alias:
+        acct: Zadejte přezdívku@doménu účtu, ze kterého se chcete přesunout
+      account_migration:
+        acct: Zadejte přezdívku@doménu účtu, na který se chcete přesunout
       account_warning_preset:
         text: Můžete používat syntaxi tootů, jako například URL, hashtagy a zmínky
       admin_account_action:
@@ -15,6 +19,8 @@ cs:
         avatar: PNG, GIF či JPG. Maximálně %{size}. Bude zmenšen na %{dimensions} px
         bot: Tento účet provádí hlavně automatizované akce a nemusí být spravován
         context: Jeden či více kontextů, ve kterých má být filtr uplatněn
+        current_password: Z bezpečnostních důvodů prosím zadejte heslo aktuálního účtu
+        current_username: Prosím potvrďte zadáním uživatelského jména aktuálního účtu
         digest: Odesíláno pouze po dlouhé době nečinnosti a pouze, pokud jste při své nepřítomnosti obdržel/a osobní zprávy
         discoverable: Adresář profilů je další způsob, díky kterému se může váš účet dostat k širšímu publiku
         email: Bude vám poslán potvrzovací e-mail
@@ -36,13 +42,15 @@ cs:
         setting_noindex: Ovlivňuje váš veřejný profil a stránky tootů
         setting_show_application: Aplikace, kterou používáte k psaní tootů, bude zobrazena v detailním zobrazení vašich tootů
         setting_use_blurhash: Gradienty jsou založeny na barvách skryté grafiky, ale zakrývají jakékoliv detaily
-        setting_use_pending_items: Skrýt aktualizace časový osy a načíst je kliknutím namísto automatického rolování proudu
+        setting_use_pending_items: Skrýt aktualizace časové osy a načíst je kliknutím namísto automatického rolování proudu
         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
       domain_allow:
         domain: Tato doména bude moci stahovat data z tohoto serveru a příchozí data z ní budou zpracována a uložena
       featured_tag:
         name: 'Nejspíš budete chtít použít jeden z těchto:'
+      form_challenge:
+        current_password: Vstupujete do zabezpečeného prostoru
       imports:
         data: Soubor CSV exportovaný z jiného serveru Mastodon
       invite_request:
@@ -58,6 +66,10 @@ cs:
         fields:
           name: Označení
           value: Obsah
+      account_alias:
+        acct: Adresa starého účtu
+      account_migration:
+        acct: Adresa nového účtu
       account_warning_preset:
         text: Text předlohy
       admin_account_action:
@@ -131,6 +143,8 @@ cs:
         must_be_follower: Blokovat oznámení od lidí, kteří vás nesledují
         must_be_following: Blokovat oznámení od lidí, které nesledujete
         must_be_following_dm: Blokovat přímé zprávy od lidí, které nesledujete
+      invite:
+        comment: Komentář
       invite_request:
         text: Proč se chcete připojit?
       notification_emails:
diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml
index 1d5ecae95..9b06bf473 100644
--- a/config/locales/simple_form.cy.yml
+++ b/config/locales/simple_form.cy.yml
@@ -2,9 +2,14 @@
 cy:
   simple_form:
     hints:
+      account_alias:
+        acct: Rhowch enwdefnyddiwr@parth y cyfrif rydych chi am symud ohono
+      account_migration:
+        acct: Rhowch enwdefnyddiwr@parth y cyfrif rydych chi am symud iddo
       account_warning_preset:
         text: Gallwch defnyddio cystrawen tŵt, fel URLs, hashnodau a sôniadau
       admin_account_action:
+        include_statuses: Bydd y defnyddiwr yn gweld pa tŵtiau sydd wedi achosi'r weithred gymedroli neu'r rhybudd
         send_email_notification: Bydd y defnyddiwr yn derbyn esboniad o beth digwyddodd gyda'i cyfrif
         text_html: Yn ddewisol. Gallwch defnyddio cystrawen tŵt. Gallwch <a href="%{path}">ychwanegu rhagosodiadau rhybydd</a> i arbed amser
         type_html: Dewis beth i wneud gyda <strong>%{acct}</strong>
@@ -14,7 +19,10 @@ cy:
         avatar: PNG, GIF neu JPG. %{size} ar y mwyaf. Caiff ei israddio i %{dimensions}px
         bot: Mae'r cyfrif hwn yn perfformio gweithredoedd awtomatig yn bennaf ac mae'n bosib nad yw'n cael ei fonitro
         context: Un neu fwy cyd-destun lle dylai'r hidlydd weithio
+        current_password: At ddibenion diogelwch, nodwch gyfrinair y cyfrif cyfredol
+        current_username: I gadarnhau, nodwch enw defnyddiwr y cyfrif cyfredol
         digest: Ond yn cael eu hanfon ar ôl cyfnod hir o anweithgarwch ac ond os ydych wedi derbyn unrhyw negeseuon personol yn eich absenoldeb
+        discoverable: Mae'r cyfeirlyfr proffil yn ffordd arall y gall eich cyfrif gyrraedd cynulleidfa ehangach
         email: Byddwch yn derbyn e-bost i gadarnhau
         fields: Mae modd i chi arddangos hyd at 4 eitem fel tabl ar eich proffil
         header: PNG, GIF neu JPG. %{size} ar y mwyaf. Ceith ei israddio i %{dimensions}px
@@ -34,16 +42,23 @@ cy:
         setting_noindex: Mae hyn yn effeithio ar eich proffil cyhoeddus a'ch tudalennau statws
         setting_show_application: Bydd y offer frydych yn defnyddio i dŵtio yn cael ei arddangos yn golwg manwl eich tŵtiau
         setting_use_blurhash: Mae graddiannau wedi'u seilio ar liwiau'r delweddau cudd ond maent yn cuddio unrhyw fanylion
+        setting_use_pending_items: Cuddio diweddariadau llinell amser y tu ôl i glic yn lle sgrolio yn awtomatig
         username: Bydd eich enw defnyddiwr yn unigryw ar %{domain}
         whole_word: Os yw'r allweddair neu'r ymadrodd yn alffaniwmerig yn unig, mi fydd ond yn cael ei osod os yw'n cyfateb a'r gair cyfan
+      domain_allow:
+        domain: Bydd y parth hwn yn gallu nôl data o'r gweinydd hwn a bydd data sy'n dod i mewn ohono yn cael ei brosesu a'i storio
       featured_tag:
         name: 'Efallai hoffech defnyddio un o''r rhain:'
+      form_challenge:
+        current_password: Rydych chi'n mynd i mewn i ardal sicr
       imports:
         data: Allforiwyd dogfen CSV o achos Mastodon arall
       invite_request:
         text: Bydd hyn yn helpu ni adolygu eich cais
       sessions:
         otp: 'Mewnbynnwch y cod dau gam a gynhyrchwyd gan eich ap ffôn neu defnyddiwch un o''ch codau adfer:'
+      tag:
+        name: Dim ond er mwyn ei gwneud yn fwy darllenadwy y gallwch chi newid y llythrennau, er enghraifft
       user:
         chosen_languages: Wedi eu dewis, dim ond tŵtiau yn yr ieithoedd hyn bydd yn cael eu harddangos mewn ffrydiau cyhoeddus
     labels:
@@ -51,9 +66,14 @@ cy:
         fields:
           name: Label
           value: Cynnwys
+      account_alias:
+        acct: Enw'r hen gyfrif
+      account_migration:
+        acct: Enw'r cyfrif newydd
       account_warning_preset:
         text: Testun rhagosodedig
       admin_account_action:
+        include_statuses: Cynhwyswch tŵtiau yr adroddwyd amdanynt yn yr e-bost
         send_email_notification: Hysbysu'r defnyddiwr trwy e-bost
         text: Rhybudd wedi'i addasu
         type: Gweithredu
@@ -108,8 +128,10 @@ cy:
         setting_show_application: Datguddio'r offer defnyddwyd i anfon tŵtiau
         setting_system_font_ui: Defnyddio ffont rhagosodedig y system
         setting_theme: Thema'r wefan
+        setting_trends: Dangos tueddiadau o heddiw ymlaen
         setting_unfollow_modal: Dangos deialog cadarnhau cyn dad-ddilyn rhywun
         setting_use_blurhash: Dangoswch raddiannau lliwgar ar gyfer cyfryngau cudd
+        setting_use_pending_items: Modd araf
         severity: Difrifoldeb
         type: Modd mewnforio
         username: Enw defnyddiwr
@@ -121,6 +143,8 @@ cy:
         must_be_follower: Blocio hysbysiadau o bobl nad ydynt yn eich dilyn
         must_be_following: Blocio hysbysiadau o bobl nad ydych yn eu dilyn
         must_be_following_dm: Blocio negeseuon uniongyrchol o bobl nad ydych yn eu dilyn
+      invite:
+        comment: Sylw
       invite_request:
         text: Pam hoffech ymuno?
       notification_emails:
@@ -132,6 +156,12 @@ cy:
         pending_account: Anfon ebost pan mae cyfrif newydd angen adolygiad
         reblog: Anfon e-bost pan mae rhywun yn bŵstio eich statws
         report: Anfon e-bost pan y cyflwynir adroddiad newydd
+        trending_tag: Anfonwch e-bost pan fydd hashnod heb ei adolygu yn tueddu
+      tag:
+        listable: Gadewch i'r hashnod hwn ymddangos mewn chwiliadau ac ar y cyfeiriadur proffil
+        name: Hashnod
+        trendable: Gadewch i'r hashnod hwn ymddangos o dan dueddiadau
+        usable: Caniatáu i tŵtiau ddefnyddio'r hashnod hwn
     'no': Na
     recommended: Argymhellwyd
     required:
diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml
index ac153805e..2ce286973 100644
--- a/config/locales/simple_form.de.yml
+++ b/config/locales/simple_form.de.yml
@@ -2,6 +2,10 @@
 de:
   simple_form:
     hints:
+      account_alias:
+        acct: Gib den benutzernamen@domain des Kontos an, von dem du umziehen möchtest
+      account_migration:
+        acct: Gib den benutzernamen@domain des Kontos an, zu dem du umziehen möchtest
       account_warning_preset:
         text: Du kannst Beitragssyntax benutzen, wie z.B. URLs, Hashtags und Erwähnungen
       admin_account_action:
@@ -15,6 +19,8 @@ de:
         avatar: PNG, GIF oder JPG. Maximal %{size}. Wird auf %{dimensions} px herunterskaliert
         bot: Dieses Konto führt lediglich automatisierte Aktionen durch und wird möglicherweise nicht überwacht
         context: Ein oder mehrere Kontexte, wo der Filter aktiv werden soll
+        current_password: Aus Sicherheitsgründen gib bitte das Passwort des aktuellen Kontos ein
+        current_username: Um das zu bestätigen, gib den Benutzernamen des aktuellen Kontos ein
         digest: Wenn du eine lange Zeit inaktiv bist, wird dir eine Zusammenfassung von Erwähnungen zugeschickt, die du in deiner Abwesenheit empfangen hast
         discoverable: Das Profilverzeichnis ist eine andere Möglichkeit, mit der dein Konto ein größeres Publikum erreichen kann
         email: Du wirst eine Bestätigungs-E-Mail erhalten
@@ -43,6 +49,8 @@ de:
         domain: Diese Domain kann Daten von diesem Server abrufen und eingehende Daten werden verarbeitet und gespeichert
       featured_tag:
         name: 'Du möchtest vielleicht einen von diesen benutzen:'
+      form_challenge:
+        current_password: Du betrittst einen sicheren Bereich
       imports:
         data: CSV-Datei, die aus einem anderen Mastodon-Server exportiert wurde
       invite_request:
@@ -58,6 +66,10 @@ de:
         fields:
           name: Bezeichnung
           value: Inhalt
+      account_alias:
+        acct: Adresse des alten Kontos
+      account_migration:
+        acct: Adresse des neuen Kontos
       account_warning_preset:
         text: Vorlagentext
       admin_account_action:
@@ -131,6 +143,8 @@ de:
         must_be_follower: Benachrichtigungen von Profilen blockieren, die mir nicht folgen
         must_be_following: Benachrichtigungen von Profilen blockieren, denen ich nicht folge
         must_be_following_dm: Private Nachrichten von Profilen, denen ich nicht folge, blockieren
+      invite:
+        comment: Kommentar
       invite_request:
         text: Warum möchtest du beitreten?
       notification_emails:
diff --git a/config/locales/simple_form.el.yml b/config/locales/simple_form.el.yml
index 4eb0ce710..53ff05de1 100644
--- a/config/locales/simple_form.el.yml
+++ b/config/locales/simple_form.el.yml
@@ -131,16 +131,18 @@ el:
         must_be_follower: Μπλόκαρε τις ειδοποιήσεις από όσους δεν ακολουθείς
         must_be_following: Μπλόκαρε τις ειδοποιήσεις που προέρχονται από άτομα που δεν τα ακολουθείς
         must_be_following_dm: Μπλόκαρε τα προσωπικά μηνύματα από όσους δεν ακολουθείς
+      invite:
+        comment: Σχόλια
       invite_request:
         text: Γιατί θέλεις να συμμετάσχεις;
       notification_emails:
         digest: Στέλνε συνοπτικά email
-        favourite: Στελνε email όταν κάποιος σημειώνει ως αγαπημένη τη δημοσίευσή σου
-        follow: Στελνε email όταν κάποιος σε ακολουθεί
-        follow_request: Στέλνε email όταν κάποιος ζητάει να σε ακολουθήσει
-        mention: Στέλνε email όταν κάποιος σε αναφέρει
+        favourite: Αποστολή email όταν κάποιος σημειώνει ως αγαπημένη τη δημοσίευσή σου
+        follow: Αποστολή email όταν κάποιος σε ακολουθεί
+        follow_request: Αποστολή email όταν κάποιος ζητάει να σε ακολουθήσει
+        mention: Αποστολή email όταν κάποιος σε αναφέρει
         pending_account: Αποστολή email όταν υπάρχει νέος λογαριασμός για επιθεώρηση
-        reblog: Στέλνε email όταν κάποιος προωθεί τη δημοσίευση σου
+        reblog: Αποστολή email όταν κάποιος προωθεί τη δημοσίευση σου
         report: Αποστολή email όταν υποβάλλεται νέα καταγγελία
         trending_tag: Αποστολή email όταν μια μη-εγκεκριμένη ταμπέλα γίνεται δημοφιλής
       tag:
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 359142064..93312a9b1 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -2,6 +2,10 @@
 en:
   simple_form:
     hints:
+      account_alias:
+        acct: Specify the username@domain of the account you want to move from
+      account_migration:
+        acct: Specify the username@domain of the account you want to move to
       account_warning_preset:
         text: You can use toot syntax, such as URLs, hashtags and mentions
       admin_account_action:
@@ -15,6 +19,8 @@ en:
         avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
         bot: This account mainly performs automated actions and might not be monitored
         context: One or multiple contexts where the filter should apply
+        current_password: For security purposes please enter the password of the current account
+        current_username: To confirm, please enter the username of the current account
         digest: Only sent after a long period of inactivity and only if you have received any personal messages in your absence
         discoverable: The profile directory is another way by which your account can reach a wider audience
         email: You will be sent a confirmation e-mail
@@ -48,6 +54,8 @@ en:
         domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored
       featured_tag:
         name: 'You might want to use one of these:'
+      form_challenge:
+        current_password: You are entering a secure area
       imports:
         data: CSV file exported from another Mastodon server
       invite_request:
@@ -63,6 +71,10 @@ en:
         fields:
           name: Label
           value: Content
+      account_alias:
+        acct: Handle of the old account
+      account_migration:
+        acct: Handle of the new account
       account_warning_preset:
         text: Preset text
       admin_account_action:
diff --git a/config/locales/simple_form.es-AR.yml b/config/locales/simple_form.es-AR.yml
new file mode 100644
index 000000000..515d5c1ed
--- /dev/null
+++ b/config/locales/simple_form.es-AR.yml
@@ -0,0 +1 @@
+es-AR:
diff --git a/config/locales/simple_form.es.yml b/config/locales/simple_form.es.yml
index 898d200d2..2fb33dbc3 100644
--- a/config/locales/simple_form.es.yml
+++ b/config/locales/simple_form.es.yml
@@ -2,6 +2,10 @@
 es:
   simple_form:
     hints:
+      account_alias:
+        acct: Especifique el nombre de usuario@dominio de la cuenta desde la cual se desea migrar
+      account_migration:
+        acct: Especifique el nombre de usuario@dominio de la cuenta a la cual se desea migrar
       account_warning_preset:
         text: Puede usar sintaxis de toots, como URLs, hashtags y menciones
       admin_account_action:
@@ -15,6 +19,8 @@ es:
         avatar: PNG, GIF o JPG. Máximo %{size}. Será escalado a %{dimensions}px
         bot: Esta cuenta ejecuta principalmente acciones automatizadas y podría no ser monitorizada
         context: Uno o múltiples contextos en los que debe aplicarse el filtro
+        current_password: Por razones de seguridad por favor ingrese la contraseña de la cuenta actual
+        current_username: Para confirmar, por favor ingrese el nombre de usuario de la cuenta actual
         digest: Solo enviado tras un largo periodo de inactividad y solo si has recibido mensajes personales durante tu ausencia
         discoverable: El directorio del perfil es otra forma en la que su cuenta puede llegar a un público más amplio
         email: Se le enviará un correo de confirmación
@@ -43,6 +49,8 @@ es:
         domain: Este dominio podrá obtener datos de este servidor y los datos entrantes serán procesados y archivados
       featured_tag:
         name: 'Puede que quieras usar uno de estos:'
+      form_challenge:
+        current_password: Estás entrando en un área segura
       imports:
         data: Archivo CSV exportado desde otra instancia de Mastodon
       invite_request:
@@ -58,6 +66,10 @@ es:
         fields:
           name: Etiqueta
           value: Contenido
+      account_alias:
+        acct: Maneja la cuenta antigua
+      account_migration:
+        acct: Maneja la cuenta nueva
       account_warning_preset:
         text: Texto predefinido
       admin_account_action:
@@ -131,6 +143,8 @@ es:
         must_be_follower: Bloquear notificaciones de personas que no te siguen
         must_be_following: Bloquear notificaciones de personas que no sigues
         must_be_following_dm: Bloquear mensajes directos de la gente que no sigues
+      invite:
+        comment: Comentar
       invite_request:
         text: "¿Por qué quiere unirse usted?"
       notification_emails:
diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml
index 90e644e55..70ad0c66a 100644
--- a/config/locales/simple_form.fa.yml
+++ b/config/locales/simple_form.fa.yml
@@ -2,9 +2,14 @@
 fa:
   simple_form:
     hints:
+      account_alias:
+        acct: نشانی username@domain را برای حسابی که می‌خواهید از آن منتقل شوید بنویسید
+      account_migration:
+        acct: نشانی username@domain را برای حسابی که می‌خواهید به آن منتقل شوید بنویسید
       account_warning_preset:
         text: می‌توانید مانند بوق‌های معمولی کاربران دیگر را نام ببرید یا پیوند و برچسب بگذارید
       admin_account_action:
+        include_statuses: این کاربر خواهد دید که کدام بوق او موجب اقدام مدیریتی یا هشدار شده است
         send_email_notification: توضیحی که کاربر می‌بینید که برای حسابش چه رخ داده است
         text_html: اختیاری. می‌توانید مثل بوق‌های معمولی بنویسید. می‌توانید برای صرفه‌جویی در زمان <a href="%{path}">هشدارهای ازپیش‌آماده بیفزایید</a>
         type_html: با حساب <strong>%{acct}</strong> می‌خواهید چه کار کنید؟‌
@@ -14,7 +19,10 @@ fa:
         avatar: یکی از قالب‌های PNG یا  GIF یا JPG. بیشترین اندازه %{size}. تصویر به اندازهٔ %{dimensions} پیکسل تبدیل خواهد شد
         bot: این حساب بیشتر به طور خودکار فعالیت می‌کند و نظارت پیوسته‌ای روی آن وجود ندارد
         context: یک یا چند زمینه که فیلتر باید در آن‌ها اعمال شود
+        current_password: به دلایل امنیتی لطفاً رمز این حساب را وارد کنید
+        current_username: برای تأیید، لطفاً نام کاربری حساب فعلی را وارد کنید
         digest: تنها وقتی فرستاده می‌شود که مدتی طولانی فعالیتی نداشته باشید و در این مدت برای شما پیغام خصوصی‌ای نوشته شده باشد
+        discoverable: فهرست گزیدهٔ کاربران این سرور راه دیگری است که با آن حساب شما می‌تواند مخاطبان بیشتری پیدا کند
         email: به شما ایمیل تأییدی فرستاده خواهد شد
         fields: شما می‌توانید تا چهار مورد را در یک جدول در نمایهٔ خود نمایش دهید
         header: یکی از قالب‌های PNG یا  GIF یا JPG. بیشترین اندازه %{size}. تصویر به اندازهٔ %{dimensions} پیکسل تبدیل خواهد شد
@@ -37,14 +45,20 @@ fa:
         setting_use_pending_items: به جای پیش‌رفتن خودکار در فهرست، به‌روزرسانی فهرست نوشته‌ها را پشت یک کلیک پنهان کن
         username: نام کاربری شما روی %{domain} یکتا خواهد بود
         whole_word: اگر کلیدواژه فقط دارای حروف و اعداد باشد، تنها وقتی پیدا می‌شود که با کل یک واژه در متن منطبق باشد، نه با بخشی از یک واژه
+      domain_allow:
+        domain: این دامین خواهد توانست داده‌ها از این سرور را دریافت کند و داده‌های از این دامین در این‌جا پردازش و ذخیره خواهند شد
       featured_tag:
         name: 'شاید بخواهید چنین چیزهایی را به کار ببرید:'
+      form_challenge:
+        current_password: شما در حال ورود به یک منطقهٔ‌ حفاظت‌شده هستید
       imports:
         data: پروندهٔ CSV که از سرور ماستدون دیگری برون‌سپاری شده
       invite_request:
         text: این برای بررسی درخواست شما به ما کمک خواهد کرد
       sessions:
         otp: 'کد تأیید دومرحله‌ای که اپ روی تلفن شما ساخته را وارد کنید یا یکی از کدهای بازیابی را به کار ببرید:'
+      tag:
+        name: شما تنها می‌توانید بزرگی و کوچکی حروف را تغییر دهید تا مثلاً آن را خواناتر کنید
       user:
         chosen_languages: اگر انتخاب کنید، تنها نوشته‌هایی که به زبان‌های برگزیدهٔ شما نوشته شده‌اند در فهرست نوشته‌های عمومی نشان داده می‌شوند
     labels:
@@ -52,9 +66,14 @@ fa:
         fields:
           name: برچسب
           value: محتوا
+      account_alias:
+        acct: نشانی حساب قدیمی
+      account_migration:
+        acct: نشانی حساب تازه
       account_warning_preset:
         text: متن از پیش آماده‌شده
       admin_account_action:
+        include_statuses: بوق‌های گزارش‌شده را در ایمیل بگنجان
         send_email_notification: اطلاع‌رسانی به کاربر از راه ایمیل
         text: هشدار موردی
         type: نوع کنش
@@ -109,6 +128,7 @@ fa:
         setting_show_application: برنامه‌ای که به کار می‌برید آشکار شود
         setting_system_font_ui: به‌کاربردن قلم پیش‌فرض سیستم
         setting_theme: تم سایت
+        setting_trends: نشان‌دادن موضوعات پرطرفدار روز
         setting_unfollow_modal: نمایش پیغام تأیید پیش از لغو پیگیری دیگران
         setting_use_blurhash: به جای تصویرهای پنهان‌شده، سایه‌های رنگی نشان بده
         setting_use_pending_items: حالت آهسته
@@ -123,6 +143,8 @@ fa:
         must_be_follower: مسدودکردن اعلان‌های همه به جز پیگیران
         must_be_following: مسدودکردن اعلان‌های کسانی که شما پی نمی‌گیرید
         must_be_following_dm: مسدودکردن پیغام‌های خصوصی کسانی که شما پی نمی‌گیرید
+      invite:
+        comment: توضیح
       invite_request:
         text: چرا می‌خواهید عضو شوید؟
       notification_emails:
@@ -134,6 +156,12 @@ fa:
         pending_account: وقتی حساب تازه‌ای نیاز به بازبینی داشت ایمیل بفرست
         reblog: وقتی کسی نوشتهٔ شما را بازبوقید ایمیل بفرست
         report: وقتی گزارش تازه‌ای فرستاده شد ایمیل بفرست
+        trending_tag: وقتی یک برچسب بازبینی‌نشده پرطرفدار شد ایمیل بفرست
+      tag:
+        listable: بگذارید که این برچسب در جستجوها و در فهرست گزیدهٔ کاربران نمایش داده شود
+        name: برچسب
+        trendable: بگذارید که این برچسب در موضوعات پرطرفدار دیده شود
+        usable: بگذارید که این برچسب در بوق‌ها به کار بروند
     'no': خیر
     recommended: توصیه می‌شود
     required:
diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml
index a92c20f10..c41292abf 100644
--- a/config/locales/simple_form.fr.yml
+++ b/config/locales/simple_form.fr.yml
@@ -2,6 +2,10 @@
 fr:
   simple_form:
     hints:
+      account_alias:
+        acct: Spécifiez le nom d'utilisateur@domaine du compte que vous souhaitez déplacer
+      account_migration:
+        acct: Spécifiez le nom d'utilisateur@domaine du compte vers lequel vous souhaitez déplacer
       account_warning_preset:
         text: Vous pouvez utiliser la syntaxe des pouets, comme les URLs, les hashtags et les mentions
       admin_account_action:
@@ -15,6 +19,8 @@ fr:
         avatar: Au format PNG, GIF ou JPG. %{size} maximum. Sera réduit à %{dimensions}px
         bot: Ce compte exécute principalement des actions automatisées et pourrait ne pas être surveillé
         context: Un ou plusieurs contextes où le filtre devrait s’appliquer
+        current_password: Pour des raisons de sécurité, veuillez saisir le mot de passe du compte courant
+        current_username: Pour confirmer, veuillez saisir le nom d'utilisateur du compte courant
         digest: Uniquement envoyé après une longue période d’inactivité et uniquement si vous avez reçu des messages personnels pendant votre absence
         discoverable: L’annuaire des profils est une autre façon pour votre compte d’atteindre une plus grand audience
         email: Vous recevrez un courriel de confirmation
@@ -43,6 +49,8 @@ fr:
         domain: Ce domaine pourra récupérer des données de ce serveur et les données entrantes seront traitées et stockées
       featured_tag:
         name: 'Vous pourriez vouloir utiliser l’un d’entre eux :'
+      form_challenge:
+        current_password: Vous entrez une zone sécurisée
       imports:
         data: Un fichier CSV généré par un autre serveur de Mastodon
       invite_request:
@@ -58,6 +66,10 @@ fr:
         fields:
           name: Étiquette
           value: Contenu
+      account_alias:
+        acct: Gestion de l'ancien compte
+      account_migration:
+        acct: Gestion du nouveau compte
       account_warning_preset:
         text: Texte de présélection
       admin_account_action:
@@ -131,6 +143,8 @@ fr:
         must_be_follower: Masquer les notifications des personnes qui ne vous suivent pas
         must_be_following: Masquer les notifications des personnes que vous ne suivez pas
         must_be_following_dm: Bloquer les messages directs des personnes que vous ne suivez pas
+      invite:
+        comment: Commentaire
       invite_request:
         text: Pourquoi voulez-vous vous inscrire ?
       notification_emails:
diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml
index adb06bc2c..61308bf48 100644
--- a/config/locales/simple_form.gl.yml
+++ b/config/locales/simple_form.gl.yml
@@ -2,6 +2,10 @@
 gl:
   simple_form:
     hints:
+      account_alias:
+        acct: Indica o usuaria@servidor da conta desde a cal queres migrar
+      account_migration:
+        acct: Indica o usuaria@servidor da conta a cal queres migrar
       account_warning_preset:
         text: Pódeslle dar formato ao toot, como URLs, etiquetas e mencións
       admin_account_action:
@@ -15,6 +19,8 @@ gl:
         avatar: PNG, GIF ou JPG.  Máximo %{size}. Será reducida a %{dimensions}px
         bot: Esta conta realiza principalmente accións automatizadas e podería non estar monitorizada
         context: Un ou varios contextos onde se debería aplicar o filtro
+        current_password: Por razóns de seguridade, introduce o contrasinal da conta actual
+        current_username: Para confirmar, introduce o nome de usuaria da conta actual
         digest: Enviar só tras un longo período de inactividade e só si recibeu algunha mensaxe persoal na súa ausencia
         discoverable: O directorio de perfil é outro xeito para que a túa conta alcance unha maior audiencia
         email: Enviaráselle un correo-e de confirmación
@@ -43,6 +49,8 @@ gl:
         domain: Este dominio estará en disposición de obter datos desde este servidor e datos de entrada a el poderán ser procesados e gardados
       featured_tag:
         name: 'Podería utilizar algunha de estas:'
+      form_challenge:
+        current_password: Estás entrando nun área segura
       imports:
         data: Ficheiro CSV exportado desde outro servidor Mastodon
       invite_request:
@@ -58,6 +66,10 @@ gl:
         fields:
           name: Etiqueta
           value: Contido
+      account_alias:
+        acct: Xestina a conta antiga
+      account_migration:
+        acct: Xestiona a nova conta
       account_warning_preset:
         text: Texto preestablecido
       admin_account_action:
@@ -131,6 +143,8 @@ gl:
         must_be_follower: Bloquear as notificacións de non-seguidoras
         must_be_following: Bloquea as notificacións de personas que non segue
         must_be_following_dm: Bloquea as mensaxes directas de personas que non segue
+      invite:
+        comment: Comentar
       invite_request:
         text: Por que quere unirse?
       notification_emails:
diff --git a/config/locales/simple_form.hu.yml b/config/locales/simple_form.hu.yml
index e3875cd6b..de1830f5d 100644
--- a/config/locales/simple_form.hu.yml
+++ b/config/locales/simple_form.hu.yml
@@ -2,9 +2,14 @@
 hu:
   simple_form:
     hints:
+      account_alias:
+        acct: Adjad meg annak a fióknak a felhasználóneve@domainjét, ahonnan át szeretnéd mozgatni
+      account_migration:
+        acct: Add meg a fióknév@domain fiókot, melybe költözni szeretnél
       account_warning_preset:
         text: Használhatod a tülkökben szokásos szintaxist, URL-eket, hashtageket, megemlítéseket
       admin_account_action:
+        include_statuses: A felhasználó látni fogja, melyik tülk okozta a moderációt vagy figyelmeztetést
         send_email_notification: A felhasználó magyarázatot kap arra, mi történt a fiókjával
         text_html: Opcionális. A tülk szintaxis használható. Egyszerűsítés végett létre is hozhatsz <a href="%{path}">figyelmeztetéseket</a>
         type_html: Megmondhatod, mi legyen vele <strong>%{acct}</strong>
@@ -14,7 +19,10 @@ hu:
         avatar: PNG, GIF vagy JPG. Maximum %{size}. Átméretezzük %{dimensions} pixelre
         bot: Ez a fiók automatikus műveleteket végez és valószínűleg nem figyeljük
         context: Kontextusok, ahol a szűrőnek működnie kell
+        current_password: Biztonsági okok miatt kérlek, írd be a jelenlegi fiók jelszavát
+        current_username: A jóváhagyáshoz írd be a jelenlegi fiók felhasználói nevét
         digest: Csak hosszú távollét esetén küldődik és csak ha személyes üzenetet kaptál távollétedben
+        discoverable: A profil adatbázis egy újabb mód, ahogyan a fiókod szélesebb tömegeket érhet el
         email: Kapsz egy megerősítő e-mailt
         fields: A profilodon legfeljebb 4 bejegyzés szerepelhet táblázatos formában
         header: PNG, GIF vagy JPG. Maximum %{size}. Átméretezzük %{dimensions} pixelre
@@ -41,6 +49,8 @@ hu:
         domain: Ez a domain adatot kérhet le a szerverünkről és az ettől érkező adatokat feldolgozzuk és mentjük
       featured_tag:
         name: 'Ezeket esetleg használhatod:'
+      form_challenge:
+        current_password: Beléptél egy biztonsági térben
       imports:
         data: Egy másik Mastodon szerverről exportált CSV fájl
       invite_request:
@@ -56,9 +66,14 @@ hu:
         fields:
           name: Címke
           value: Tartalom
+      account_alias:
+        acct: Régi fiók kezelése
+      account_migration:
+        acct: Új fiók kezelése
       account_warning_preset:
         text: Figyelmeztető szöveg
       admin_account_action:
+        include_statuses: Helyezd az e-mailbe a jelentett tülköket
         send_email_notification: Figyelmeztessük a felhasználót e-mailben
         text: Egyedi figyelmeztetés
         type: Művelet
@@ -128,6 +143,8 @@ hu:
         must_be_follower: Nem követőidtől érkező értesítések tiltása
         must_be_following: Nem követettjeidtől érkező értesítések tiltása
         must_be_following_dm: Nem követettjeidtől érkező üzenetek tiltása
+      invite:
+        comment: Hozzászólás
       invite_request:
         text: Miért akarsz csatlakozni?
       notification_emails:
@@ -142,6 +159,7 @@ hu:
         trending_tag: E-mail küldése, ha egy még nem látott hashtag trendi lett
       tag:
         listable: A hashtag megjelenhet a profiladatbázisban
+        name: Címke
         trendable: A hashtag megjelenhet a trendek között
         usable: Tülkök használhatják ezt a hashtaget
     'no': Nem
diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml
index f64a85151..eeb1eee51 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -2,6 +2,10 @@
 ja:
   simple_form:
     hints:
+      account_alias:
+        acct: 引っ越し元のユーザー名@ドメインを指定してください
+      account_migration:
+        acct: 引っ越し先のユーザー名@ドメインを指定してください
       account_warning_preset:
         text: URL、ハッシュタグ、メンションなど、投稿に用いる構文が使用できます
       admin_account_action:
@@ -15,6 +19,8 @@ ja:
         avatar: "%{size}までのPNG、GIF、JPGが利用可能です。%{dimensions}pxまで縮小されます"
         bot: このアカウントは主に自動で動作し、人が見ていない可能性があります
         context: フィルターを適用する対象 (複数選択可)
+        current_password: 現在のアカウントのパスワードを入力してください
+        current_username: 確認のため、現在のアカウントのユーザー名を入力してください
         digest: 長期間使用していない場合と不在時に返信を受けた場合のみ送信されます
         discoverable: ディレクトリはあなたのアカウントをより多くの人に見つけてもらうためのひとつの手段です
         email: 確認のメールが送信されます
@@ -43,6 +49,8 @@ ja:
         domain: 登録するとこのサーバーからデータを受信したり、このドメインから受信するデータを処理して保存できるようになります
       featured_tag:
         name: 'これらを使うといいかもしれません:'
+      form_challenge:
+        current_password: セキュリティ上重要なエリアにアクセスしています
       imports:
         data: 他の Mastodon サーバーからエクスポートしたCSVファイルを選択して下さい
       invite_request:
@@ -58,6 +66,10 @@ ja:
         fields:
           name: ラベル
           value: 内容
+      account_alias:
+        acct: 引っ越し元のユーザー ID
+      account_migration:
+        acct: 引っ越し先のユーザー ID
       account_warning_preset:
         text: プリセット警告文
       admin_account_action:
@@ -132,6 +144,8 @@ ja:
         must_be_follower: フォロワー以外からの通知をブロック
         must_be_following: フォローしていないユーザーからの通知をブロック
         must_be_following_dm: フォローしていないユーザーからのダイレクトメッセージをブロック
+      invite:
+        comment: コメント
       invite_request:
         text: 意気込みをお聞かせください
       notification_emails:
diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml
index 118bf50d4..e89f9be00 100644
--- a/config/locales/simple_form.ko.yml
+++ b/config/locales/simple_form.ko.yml
@@ -2,6 +2,10 @@
 ko:
   simple_form:
     hints:
+      account_alias:
+        acct: 이동하고자 하는 계정의 사용자이름@도메인을 설정하세요
+      account_migration:
+        acct: 이동하고자 하는 목적지 계정의 사용자이름@도메인을 설정하세요
       account_warning_preset:
         text: URL, 해시태그, 멘션과 같은 툿 문법을 사용할 수 있습니다
       admin_account_action:
@@ -12,14 +16,16 @@ ko:
         warning_preset_id: 선택사항. 틀의 마지막에 임의의 텍스트를 추가 할 수 있습니다
       defaults:
         autofollow: 이 초대를 통해 가입하는 사람은 당신을 자동으로 팔로우 하게 됩니다
-        avatar: PNG, GIF 혹은 JPG. 최대 %{size}. %{dimensions}px로 다운스케일 될 것임
+        avatar: PNG, GIF 혹은 JPG. 최대 %{size}. %{dimensions}px로 축소 됨
         bot: 사람들에게 계정이 사람이 아님을 알립니다
         context: 필터를 적용 할 한 개 이상의 컨텍스트
+        current_password: 보안을 위해 현재 계정의 비밀번호를 입력해주세요
+        current_username: 확인을 위해, 현재 계정의 유저명을 입력해주세요
         digest: 오랫동안 활동하지 않았을 때 받은 멘션들에 대한 요약 받기
         discoverable: 프로필 디렉터리는 내 계정이 더 많은 관심을 갖게 할 수 있는 다른 방법입니다
         email: 당신은 확인 메일을 받게 됩니다
         fields: 당신의 프로파일에 최대 4개까지 표 형식으로 나타낼 수 있습니다
-        header: PNG, GIF 혹은 JPG. 최대 %{size}. %{dimensions}px로 다운스케일 됨
+        header: PNG, GIF 혹은 JPG. 최대 %{size}. %{dimensions}px로 축소 됨
         inbox_url: 사용 할 릴레이 서버의 프론트페이지에서 URL을 복사합니다
         irreversible: 필터링 된 툿은 나중에 필터가 사라지더라도 돌아오지 않게 됩니다
         locale: 유저 인터페이스, 이메일, 푸시 알림 언어
@@ -43,6 +49,8 @@ ko:
         domain: 이 도메인은 이 서버에서 데이터를 가져갈 수 있고 이 도메인에서 보내진 데이터는 처리되고 저장 됩니다
       featured_tag:
         name: '이것들을 사용하면 좋을 것 같습니다:'
+      form_challenge:
+        current_password: 당신은 보안 구역에 진입하고 있습니다
       imports:
         data: 다른 마스토돈 서버에서 추출된 CSV 파일
       invite_request:
@@ -58,6 +66,10 @@ ko:
         fields:
           name: 라벨
           value: 내용
+      account_alias:
+        acct: 기존 계정의 핸들
+      account_migration:
+        acct: 새 계정의 핸들
       account_warning_preset:
         text: 프리셋 텍스트
       admin_account_action:
@@ -131,6 +143,8 @@ ko:
         must_be_follower: 나를 팔로우 하지 않는 사람에게서 온 알림을 차단
         must_be_following: 내가 팔로우 하지 않는 사람에게서 온 알림을 차단
         must_be_following_dm: 내가 팔로우 하지 않은 사람에게서 오는 다이렉트메시지를 차단
+      invite:
+        comment: 주석
       invite_request:
         text: 가입하려는 이유가 무엇인가요?
       notification_emails:
diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml
index cda4e9ead..77445b0cb 100644
--- a/config/locales/simple_form.nl.yml
+++ b/config/locales/simple_form.nl.yml
@@ -2,9 +2,14 @@
 nl:
   simple_form:
     hints:
+      account_alias:
+        acct: Vul de gebruikersnaam@domein van het account in, die je wilt verhuizen
+      account_migration:
+        acct: Vul de gebruikersnaam@domein van het account in, waarnaartoe je wilt verhuizen
       account_warning_preset:
         text: Je kunt voor toots specifieke tekst gebruiken, zoals URL's, hashtags en vermeldingen
       admin_account_action:
+        include_statuses: De gebruiker ziet welke toots verantwoordelijk zijn voor de moderatieactie of waarschuwing
         send_email_notification: De gebruiker ontvangt een uitleg over wat er met hun account is gebeurd
         text_html: Optioneel. Je kunt voor toots specifieke tekst gebruiken. Om tijd te besparen kun je <a href="%{path}">voorinstellingen van waarschuwingen toevoegen</a>
         type_html: Kies wat er met <strong>%{acct}</strong> moet gebeuren
@@ -14,7 +19,10 @@ nl:
         avatar: PNG, GIF of JPG. Maximaal %{size}. Wordt teruggeschaald naar %{dimensions}px
         bot: Dit is een geautomatiseerd account en wordt mogelijk niet gemonitord
         context: Een of meerdere locaties waar de filter actief moet zijn
+        current_password: Voer voor veiligheidsredenen het wachtwoord van je huidige account in
+        current_username: Voer ter bevestiging de gebruikersnaam van je huidige account in
         digest: Wordt alleen na een lange periode van inactiviteit verzonden en alleen wanneer je tijdens jouw afwezigheid persoonlijke berichten hebt ontvangen
+        discoverable: De gebruikersgids is een andere manier waarmee jouw account een groter publiek kan bereiken
         email: Je krijgt een bevestigingsmail
         fields: Je kan maximaal 4 items als een tabel op je profiel weergeven
         header: PNG, GIF of JPG. Maximaal %{size}. Wordt teruggeschaald naar %{dimensions}px
@@ -33,16 +41,24 @@ nl:
         setting_hide_network: Wie jij volgt en wie jou volgen wordt niet op jouw profiel getoond
         setting_noindex: Heeft invloed op jouw openbare profiel en toots
         setting_show_application: De toepassing de je gebruikt om te tooten wordt in de gedetailleerde weergave van de toot getoond
+        setting_use_blurhash: Wazige kleurovergangen zijn gebaseerd op de kleuren van de verborgen media, waarmee elk detail verdwijnt
+        setting_use_pending_items: De tijdlijn wordt bijgewerkt door op het aantal nieuwe items te klikken, in plaats van dat deze automatisch wordt bijgewerkt
         username: Jouw gebruikersnaam is uniek op %{domain}
         whole_word: Wanneer het trefwoord of zinsdeel alfanumeriek is, wordt het alleen gefilterd wanneer het hele woord overeenkomt
+      domain_allow:
+        domain: Dit domein is in staat om gegevens van deze server op te halen, en binnenkomende gegevens worden verwerkt en opgeslagen
       featured_tag:
         name: 'Je wilt misschien een van deze gebruiken:'
+      form_challenge:
+        current_password: Je betreedt een veilige omgeving
       imports:
         data: CSV-bestand dat op een andere Mastodonserver werd geëxporteerd
       invite_request:
         text: Dit helpt ons om jouw aanvraag te beoordelen
       sessions:
         otp: 'Voer de tweestaps-aanmeldcode vanaf jouw mobiele telefoon in of gebruik een van jouw herstelcodes:'
+      tag:
+        name: Je kunt elk woord met een hoofdletter beginnen, om zo bijvoorbeeld de tekst leesbaarder te maken
       user:
         chosen_languages: Alleen toots in de aangevinkte talen worden op de openbare tijdlijnen getoond
     labels:
@@ -50,9 +66,14 @@ nl:
         fields:
           name: Label
           value: Inhoud
+      account_alias:
+        acct: Mastodonadres van het oude account
+      account_migration:
+        acct: Mastodonadres van het nieuwe account
       account_warning_preset:
         text: Tekst van voorinstelling
       admin_account_action:
+        include_statuses: Gerapporteerde toots aan de e-mail toevoegen
         send_email_notification: Meld dit per e-mail aan de gebruiker
         text: Aangepaste waarschuwing
         type: Actie
@@ -107,7 +128,9 @@ nl:
         setting_show_application: Toepassing onthullen die je voor het verzenden van toots gebruikt
         setting_system_font_ui: Standaardlettertype van jouw systeem gebruiken
         setting_theme: Thema website
+        setting_trends: Trends van vandaag tonen
         setting_unfollow_modal: Vraag voor het ontvolgen van iemand een bevestiging
+        setting_use_blurhash: Wazige kleurovergangen voor verborgen media tonen
         setting_use_pending_items: Langzame modus
         severity: Zwaarte
         type: Importtype
@@ -120,6 +143,8 @@ nl:
         must_be_follower: Meldingen van mensen die jou niet volgen blokkeren
         must_be_following: Meldingen van mensen die jij niet volgt blokkeren
         must_be_following_dm: Directe berichten van mensen die jij niet volgt blokkeren
+      invite:
+        comment: Opmerking
       invite_request:
         text: Waarom wil jij je aanmelden?
       notification_emails:
@@ -131,8 +156,12 @@ nl:
         pending_account: Een e-mail verzenden wanneer een nieuw account moet worden beoordeeld
         reblog: Een e-mail versturen wanneer iemand jouw toot heeft geboost
         report: Verstuur een e-mail wanneer een nieuw rapportage is ingediend
+        trending_tag: Een e-mail versturen wanneer een nog niet beoordeelde hashtag trending is
       tag:
+        listable: Toestaan dat deze hashtag in zoekopdrachten en in de gebruikersgids te zien valt
         name: Hashtag
+        trendable: Toestaan dat deze hashtag onder trends te zien valt
+        usable: Toestaan dat deze hashtag in toots gebruikt mag worden
     'no': Nee
     recommended: Aanbevolen
     required:
diff --git a/config/locales/simple_form.oc.yml b/config/locales/simple_form.oc.yml
index 9336a9846..59651d9de 100644
--- a/config/locales/simple_form.oc.yml
+++ b/config/locales/simple_form.oc.yml
@@ -2,9 +2,14 @@
 oc:
   simple_form:
     hints:
+      account_alias:
+        acct: Donatz l’utilizaire@domeni del compte que volètz desplaçar
+      account_migration:
+        acct: Donatz l’utilizaire@domeni del compte ont volètz anar
       account_warning_preset:
         text: Podètz utilizar la sintaxi dels tuts, coma las URL, las etiquetas e las mencions
       admin_account_action:
+        include_statuses: L’utilizaire veiràs quals tuts a provocat l’accion de moderacion o avertiment
         send_email_notification: L’utilizaire recebrà una explicacion de çò qu’arribèt a son compte
         text_html: Opcional. Podètz utilizar la sintaxi dels tuts. Podètz <a href="%{path}">ajustar un avertiment personalizat</a> per estalviar de temps
         type_html: Causir de qué far amb <strong>%{acct}</strong>
@@ -14,7 +19,10 @@ oc:
         avatar: PNG, GIF o JPG. Maximum %{size}. Serà retalhat en %{dimensions}px
         bot: Avisar lo monde qu’aqueste compte es pas d’una persona
         context: Un o mai de contèxtes ont lo filtre deuriá s’aplicar
+        current_password: Per de rasons de seguretat volgatz picar lo senhal del compte actual
+        current_username: Per confirmar, volgatz picar lo nom d’utilizaire del compte actual
         digest: Solament enviat aprèp un long moment d’inactivitat e solament s’avètz recebut de messatges personals pendent vòstra abséncia
+        discoverable: L’annuari de perfiles es un biais mai per que vòstre compte aja una audiéncia mai granda
         email: Vos mandarem un corrièl de confirmacion
         fields: Podètz far veire cap a 4 elements sus vòstre perfil
         header: PNG, GIF o JPG. Maximum %{size}. Serà retalhada en %{dimensions}px
@@ -37,14 +45,20 @@ oc:
         setting_use_pending_items: Rescondre las actualizacions del flux d’actualitat aprèp un clic allòc de desfilar lo flux automaticament
         username: Vòstre nom d’utilizaire serà unic sus %{domain}
         whole_word: Quand lo mot-clau o frasa es solament alfranumeric, serà pas qu’aplicat se correspond al mot complèt
+      domain_allow:
+        domain: Aqueste domeni poirà recuperar las donadas d’aqueste servidor estant e las donadas venent d’aqueste domeni seràn tractadas e gardadas
       featured_tag:
         name: 'Benlèu que volètz utilizar una d’aquestas causas :'
+      form_challenge:
+        current_password: Dintratz dins una zòna segura
       imports:
         data: Fichièr CSV exportat d’un autre servidor Mastodon
       invite_request:
         text: Aquò nos ajudarà per validar vòstra demanda
       sessions:
         otp: 'Picatz lo còdi d’autentificacion en dos temps (Two factor code) de vòstra aplicacion mobil o utilizatz un de vòstres còdis de recuperacion :'
+      tag:
+        name: Podètz pas que cambiar la talha de las letras, per exemple, per que sián de melhor legir
       user:
         chosen_languages: Quand seleccionadas, solament los tuts dins las lengas triadas seràn mostrats dins vòstre flux d’actualitat
     labels:
@@ -52,9 +66,14 @@ oc:
         fields:
           name: Nom
           value: Contengut
+      account_alias:
+        acct: Identificant de l’ancian compte
+      account_migration:
+        acct: Identificant del nòu compte
       account_warning_preset:
         text: Tèxt predefinit
       admin_account_action:
+        include_statuses: Inclure los tuts senhalats dins lo corrièl
         send_email_notification: Avisar l’utilizaire per corrièl
         text: Avertiment personalizat
         type: Accions
@@ -124,6 +143,8 @@ oc:
         must_be_follower: Blocar las notificacions del mond que vos sègon pas
         must_be_following: Blocar las notificacions del mond que seguètz pas
         must_be_following_dm: Blocar los messatges del monde que seguètz pas
+      invite:
+        comment: Comentari
       invite_request:
         text: Perqué volètz vos marcar ?
       notification_emails:
@@ -135,6 +156,12 @@ oc:
         pending_account: Enviar un corrièl quand cal validar un compte novèl
         reblog: Enviar un corrièl quand qualqu’un tòrna partejar vòstre estatut
         report: Enviar un corrièl pels nòus senhalaments
+        trending_tag: Enviar un corrièl quand una etiqueta pas repassada es en tendéncia
+      tag:
+        listable: Permetre a aquesta etiqueta d’aparéisser a las recèrcas e a l’annuari de perfils
+        name: Etiqueta
+        trendable: Permetre a aquesta etiqueta d’aparéisser a las tendéncias
+        usable: Permetre als tuts d’utilizar aquesta etiqueta
     'no': Non
     recommended: Recomandat
     required:
diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml
index 8400951f0..3f3f78180 100644
--- a/config/locales/simple_form.pt-BR.yml
+++ b/config/locales/simple_form.pt-BR.yml
@@ -2,9 +2,14 @@
 pt-BR:
   simple_form:
     hints:
+      account_alias:
+        acct: Especifique o usuário@domínio da conta da qual você deseja mover
+      account_migration:
+        acct: Especifique o usuário@domínio da conta para o qual você deseja mover
       account_warning_preset:
         text: Você pode usar a sintaxe de um toot, como URLs, hashtags e menções
       admin_account_action:
+        include_statuses: O usuário verá quais toots causaram o aviso ou ação da moderação
         send_email_notification: O usuário vai receber uma explicação do que aconteceu com a sua conta
         text_html: Opcional. Você pode usar a sintaxe de toots. Você pode <a href="%{path}">adicionar avisos pré-definidos</a> para ganhar tempo
         type_html: Escolha o que fazer com <strong>%{acct}</strong>
@@ -14,6 +19,8 @@ pt-BR:
         avatar: PNG, GIF or JPG. Arquivos de até %{size}. Eles serão diminuídos para %{dimensions}px
         bot: Essa conta executa principalmente ações automatizadas e pode não ser monitorada
         context: Um ou mais contextos onde o filtro deve ser aplicado
+        current_password: Para fins de segurança digite a senha da conta atual
+        current_username: Para confirmar, por favor, digite o usuário da conta atual
         digest: Enviado após um longo período de inatividade com um resumo das menções que você recebeu em sua ausência
         email: Você receberá um email de confirmação
         fields: Você pode ter até 4 itens exibidos em forma de tabela no seu perfil
@@ -26,16 +33,21 @@ pt-BR:
         phrase: Vai coincidir, independente de maiúsculas ou minúsculas, no texto ou no aviso de conteúdo de um toot
         scopes: Quais APIs a aplicação vai ter permissão de acessar. Se você selecionar um escopo de alto nível, você não precisa selecionar individualmente os outros.
         setting_aggregate_reblogs: Não mostrar novos compartilhamentos para toots que foram compartilhados recentemente (afeta somente novos compartilhamentos recebidos)
+        setting_default_sensitive: Mídia sensível está oculta por padrão e pode ser revelada com um clique
         setting_display_media_default: Esconder mídia marcada como sensível
         setting_display_media_hide_all: Sempre esconder todas as mídias
         setting_display_media_show_all: Sempre mostrar mídia marcada como sensível
         setting_hide_network: Quem você segue e quem segue você não serão exibidos no seu perfil
         setting_noindex: Afeta seu perfil público e as páginas de suas postagens
         setting_show_application: A aplicação que você usar para enviar seus toots vai aparecer na visão detalhada dos seus toots
+        setting_use_blurhash: Os gradientes são baseados nas cores das imagens escondidas, mas ofuscam quaisquer detalhes
+        setting_use_pending_items: Ocultar atualizações de linha de tempo atrás de um clique ao invés de rolar automaticamente o feed
         username: Seu nome de usuário será único em %{domain}
         whole_word: Quando a palavra ou frase é inteiramente alfanumérica, ela será aplicada somente se corresponder a palavra inteira
       featured_tag:
         name: 'Você pode querer usar um destes:'
+      form_challenge:
+        current_password: Você está entrando em uma área segura
       imports:
         data: Arquivo CSV exportado de outra instância do Mastodon
       invite_request:
@@ -52,6 +64,7 @@ pt-BR:
       account_warning_preset:
         text: Texto pré-definido
       admin_account_action:
+        include_statuses: Incluir toots reportados no e-mail
         send_email_notification: Notificar o usuário por e-mail
         text: Aviso customizado
         type: Ação
@@ -63,6 +76,7 @@ pt-BR:
         warning_preset_id: Usar um aviso pré-definido
       defaults:
         autofollow: Convite para seguir a sua conta
+        avatar: Imagem de Perfil
         bot: Esta é uma conta-robô
         chosen_languages: Filtros de idioma
         confirm_new_password: Confirmar nova senha
@@ -82,6 +96,7 @@ pt-BR:
         locked: Trancar conta
         max_uses: Número máximo de usos
         new_password: Nova senha
+        note: Biografia
         otp_attempt: Código de autenticação em dois passos
         password: Senha
         phrase: Palavra-chave ou frase
@@ -109,10 +124,14 @@ pt-BR:
         username: Nome de usuário
         username_or_email: Nome de usuário ou e-mail
         whole_word: Palavra inteira
+      featured_tag:
+        name: Hashtag
       interactions:
         must_be_follower: Bloquear notificações de não-seguidores
         must_be_following: Bloquear notificações de pessoas que você não segue
         must_be_following_dm: Bloquear mensagens diretas de pessoas que você não segue
+      invite:
+        comment: Comentário
       invite_request:
         text: Por que você quer se cadastrar?
       notification_emails:
@@ -124,7 +143,15 @@ pt-BR:
         pending_account: Mandar um -mail quando uma nova conta precisar ser revisada
         reblog: Mandar um e-mail quando alguém compartilhar suas postagens
         report: Mandar um e-mail quando uma nova denúncia é submetida
+        trending_tag: Enviar e-mail quando uma hashtag não revisada estiver em alta
+      tag:
+        listable: Permitir que esta hashtag apareça em pesquisas e no diretório de perfis
+        name: Hashtag
+        trendable: Permitir que esta hashtag apareça em alta
+        usable: Permitir que toots usem esta hastag
     'no': Não
+    recommended: Recomendado
     required:
+      mark: "*"
       text: obrigatório
     'yes': Sim
diff --git a/config/locales/simple_form.pt-PT.yml b/config/locales/simple_form.pt-PT.yml
index 0ac31f8c2..57acde4d9 100644
--- a/config/locales/simple_form.pt-PT.yml
+++ b/config/locales/simple_form.pt-PT.yml
@@ -2,9 +2,14 @@
 pt-PT:
   simple_form:
     hints:
+      account_alias:
+        acct: Especifique o nome de usuário@domínio da conta de onde você deseja mover
+      account_migration:
+        acct: Especifique o nome de usuário@domínio da conta para onde você deseja mover
       account_warning_preset:
         text: Tu podes usar sintaxe de escrita, como URLs, hashtags e referências
       admin_account_action:
+        include_statuses: O usuário verá quais ferramentas causaram a ação de moderação ou aviso
         send_email_notification: O utilizador receberá uma explicação sobre o que aconteceu com a sua conta
         text_html: Opcional. Tu podes usar sintaxe de escrita. Tu podes <a href="%{path}"> adicionar predefinições de aviso</a> para poupar tempo
         type_html: Escolhe o que fazer com <strong>%{acct}</strong>
@@ -14,6 +19,7 @@ pt-PT:
         avatar: PNG, GIF or JPG. Arquivos até %{size}. Vão ser reduzidos para %{dimensions}px
         bot: Esta conta executa essencialmente acções automáticas e pode não poder ser monitorizada
         context: Um ou múltiplos contextos nos quais o filtro deve ser aplicado
+        current_password: Para fins de segurança, por favor, digite a senha da conta atual
         digest: Enviado após um longo período de inatividade e apenas se foste mencionado na tua ausência
         email: Será enviado um e-mail de confirmação
         fields: Podes ter até 4 itens expostos, em forma de tabela, no teu perfil
diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml
index 8caae951c..869231bdf 100644
--- a/config/locales/simple_form.th.yml
+++ b/config/locales/simple_form.th.yml
@@ -123,6 +123,8 @@ th:
         must_be_follower: ปิดกั้นการแจ้งเตือนจากที่ไม่ใช่ผู้ติดตาม
         must_be_following: ปิดกั้นการแจ้งเตือนจากผู้คนที่คุณไม่ได้ติดตาม
         must_be_following_dm: ปิดกั้นข้อความโดยตรงจากผู้คนที่คุณไม่ได้ติดตาม
+      invite:
+        comment: ความคิดเห็น
       invite_request:
         text: ทำไมคุณจึงต้องการเข้าร่วม?
       notification_emails:
diff --git a/config/locales/simple_form.uk.yml b/config/locales/simple_form.uk.yml
index 1e4a262e7..a6ae14f6d 100644
--- a/config/locales/simple_form.uk.yml
+++ b/config/locales/simple_form.uk.yml
@@ -82,6 +82,7 @@ uk:
         discoverable: Оприлюднити обліковий запис у каталозі
         display_name: Ім'я
         email: Email адреса
+        expires_in: Закінчується після
         fields: Метадані профіля
         header: Заголовок
         inbox_url: URL поштової скриньки ретранслятора
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index e6a30f0c3..08f144c25 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -17,9 +17,6 @@ sk:
     contact_unavailable: Neuvedený/á
     discover_users: Objavuj užívateľov
     documentation: Dokumentácia
-    extended_description_html: |
-      <h3>Pravidlá</h3>
-      <p>Žiadne zatiaľ uvedené nie sú</p>
     federation_hint_html: S účtom na %{instance} budeš môcť následovať ľúdí na hociakom Mastodon serveri, ale aj na iných serveroch.
     generic_description: "%{domain} je jeden server v sieti"
     get_apps: Vyskúšaj aplikácie
@@ -40,6 +37,9 @@ sk:
     status_count_before: Ktorí napísali
     tagline: Následuj kamarátov, a objavuj nových
     terms: Podmienky užitia
+    unavailable_content: Nedostupný obsah
+    unavailable_content_description:
+      reason: 'Dôvod:'
     user_count_after:
       few: užívateľov
       many: užívatelia
@@ -246,8 +246,10 @@ sk:
       disabled_msg: Emoji bolo úspešne zakázané
       emoji: Emotikony
       enable: Povoľ
+      enabled: Povolené
       enabled_msg: Emoji bolo úspešne povolené
       image_hint: PNG do 50KB
+      list: Zoznam
       listed: V zozname
       new:
         title: Pridaj nové, vlastné emoji
@@ -256,11 +258,13 @@ sk:
       shortcode_hint: Aspoň 2 znaky, povolené sú alfanumerické, alebo podčiarkovník
       title: Vlastné emoji
       uncategorized: Nezaradené
+      unlist: Nezaraď
       unlisted: Nie je na zozname
       update_failed_msg: Nebolo možné aktualizovať toto emoji
       updated_msg: Emoji bolo úspešne aktualizované!
       upload: Nahraj
     dashboard:
+      authorized_fetch_mode: Autorizovaný režim
       backlog: odložené aktivity
       config: Nastavenia
       feature_deletions: Vymazanie účtov
@@ -436,6 +440,8 @@ sk:
       custom_css:
         desc_html: Uprav vzhľad pomocou CSS, ktoré je načítané na každej stránke
         title: Vlastné CSS
+      default_noindex:
+        desc_html: Ovplyvňuje všetkých užívateľov, ktorí si toto nasavenie nezmenili sami
       domain_blocks:
         all: Všetkým
         disabled: Nikomu
@@ -527,6 +533,10 @@ sk:
       context: Súvis
       directory: V zozname
       in_directory: "%{count} v zozname"
+      last_active: Naposledy aktívny
+      most_popular: Najpopulárnejšie
+      most_recent: Najnovšie
+      name: Haštag
       review: Prehodnoť stav
       reviewed: Zhodnotené
       title: Haštagy
@@ -551,6 +561,9 @@ sk:
       subject: Nové hlásenie pre %{instance} (#%{id})
     new_trending_tag:
       subject: Nový haštag očakáva preverenie na %{instance} (#%{name})
+  aliases:
+    add_new: Vytvor alias
+    remove: Odpoj alias
   appearance:
     advanced_web_interface: Pokročilé webové rozhranie
     advanced_web_interface_hint: 'Ak chceš využiť celkovú šírku tvojej obrazovky, pokročilé webové rozhranie ti umožňuje nastaviť mnoho rôznych stĺpcov, aby si videl/a toľko informácií naraz, koľko chceš: Domov, oboznámenia, federovanú časovú os, a ľubovolný počet zoznamov, či haštagov.'
@@ -607,6 +620,7 @@ sk:
       confirming: Čaká sa na dokončenie potvrdenia emailom.
       functional: Tvoj účet je plne funkčný.
       pending: Tvoja žiadosť čaká na schvílenie od nášho týmu. Môže to chviľu potrvať. Ak bude tvoja žiadosť schválená, dostaneš o tom email.
+      redirecting_to: Tvoj účet je neaktívny, lebo v súčasnosti presmerováva na %{acct}.
     trouble_logging_in: Problém s prihlásením?
   authorize_follow:
     already_following: Tento účet už následuješ
@@ -619,6 +633,10 @@ sk:
       return: Ukáž užívateľov profil
       web: Prejdi do siete
     title: Následuj %{acct}
+  challenge:
+    confirm: Pokračuj
+    invalid_password: Nesprávne heslo
+    prompt: Pre pokračovanie potvrď svoje heslo
   datetime:
     distance_in_words:
       about_x_hours: "%{count}hod"
@@ -635,6 +653,7 @@ sk:
       x_seconds: "%{count}sek"
   deletes:
     confirm_password: Napíšte svoje terajšie heslo pre overenie vašej identity
+    confirm_username: Zadaj svoju prezývku, na potvrdenie úkonu
     proceed: Vymaž účet
     success_msg: Tvoj účet bol úspešne vymazaný
     warning:
@@ -648,21 +667,6 @@ sk:
     directory: Katalóg profilov
     explanation: Pátraj po užívateľoch podľa ich záujmov
     explore_mastodon: Prebádaj %{title}
-  domain_blocks:
-    blocked_domains: Zoznam obmedzovaných a blokovaných domén
-    description: Toto je zoznam serverov, ktorých federáciu %{instance} obmedzuje, alebo nepríjma.
-    domain: Doména
-    media_block: Blokovanie médií
-    no_domain_blocks: "(Žiadne domény niesú blokované)"
-    severity: Závažnosť
-    severity_legend:
-      media_block: Mediálne súbory zo servera niesú ani zachytávané, ani ukladané, či zobrazované užívateľovi.
-      suspension_disclaimer: Vylúčené servery sa môžu občas dostať k verejnému obsahu tohto servera.
-      title: Závažnosti
-    show_rationale: Ukáž zdôvodnenie
-    silence: Stíš
-    suspension: Vylúčenie
-    title: Zoznam instancií, ktoré blokuje %{instance}
   domain_validator:
     invalid_domain: nieje správny tvar domény
   errors:
@@ -805,9 +809,20 @@ sk:
       too_many: Nemôžeš priložiť viac ako 4 súbory
   migrations:
     acct: prezývka@doména nového účtu
-    currently_redirecting: 'Tvoj profil má nastavené presmerovanie na:'
-    proceed: Uložiť
-    updated_msg: Tvoje nastavenia pre presmerovanie účtu boli úspešne aktualizované!
+    cancel: Zruš presmerovanie
+    cancelled_msg: Presmerovanie úspešne zrušené.
+    errors:
+      missing_also_known_as: neodkazuje spätne na tento účet
+      move_to_self: nemôže to byť tvoj súčasný účet
+      not_found: nebolo možné nájsť
+    followers_count: Následovatelia v čase presunu
+    incoming_migrations: Presúvam sa z iného účtu
+    not_redirecting: Tvoj účet v súčasnosti nepresmerováva na žiaden iný účet.
+    past_migrations: Predošlé presuny
+    proceed_with_move: Presuň sledovateľov
+    redirecting_to: Tvoj účet presmerováva na %{acct}.
+    warning:
+      other_data: Žiadne iné dáta nebudú presunuté automaticky
   moderation:
     title: Moderovanie
   notification_mailer:
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index 47b835646..63eed6409 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -17,9 +17,6 @@ sl:
     contact_unavailable: Ni na voljo
     discover_users: Odkrijte uporabnike
     documentation: Dokumentacija
-    extended_description_html: |
-      <h3>Dober prostor za pravila</h3>
-      <p>Razširjen opis še ni bil nastavljen.</p>
     federation_hint_html: Z računom na %{instance} boste lahko spremljali ljudi na kateremkoli Mastodon strežniku.
     generic_description: "%{domain} je en strežnik v omrežju"
     get_apps: Poskusite mobilno aplikacijo
@@ -734,9 +731,6 @@ sl:
       too_many: Ni možno priložiti več kot 4 datoteke
   migrations:
     acct: username@domain novega računa
-    currently_redirecting: 'Vaš profil je preusmerjen na:'
-    proceed: Shrani
-    updated_msg: Nastavitev selitve računa je bila uspešno posodobljena!
   moderation:
     title: Moderiranje
   notification_mailer:
diff --git a/config/locales/sq.yml b/config/locales/sq.yml
index 4e5f37294..af180e281 100644
--- a/config/locales/sq.yml
+++ b/config/locales/sq.yml
@@ -9,9 +9,6 @@ sq:
     contact: Kontakt
     contact_missing: I parregulluar
     documentation: Dokumentim
-    extended_description_html: |
-      <h3>Një vend i mirë për rregulla</h3>
-      <p>Përshkrimi i zgjeruar s’është sajuar ende.</p>
     generic_description: "%{domain} është një shërbyes te rrjeti"
     hosted_on: Mastodon i strehuar në %{domain}
     learn_more: Mësoni më tepër
@@ -602,9 +599,6 @@ sq:
       too_many: S’mund të bashkëngjiten më shumë se 4 kartela
   migrations:
     acct: emërpërdoruesi@përkatësi e llogarisë së re
-    currently_redirecting: 'Profili juaj është caktuar të ridrejtojë te:'
-    proceed: Ruaje
-    updated_msg: Rregullimi juaj për migrim llogarish u përditësua me sukses!
   moderation:
     title: Moderim
   notification_mailer:
diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml
index 5c06242cc..44bae34d0 100644
--- a/config/locales/sr-Latn.yml
+++ b/config/locales/sr-Latn.yml
@@ -6,9 +6,6 @@ sr-Latn:
     about_this: O instanci
     contact: Kontakt
     contact_missing: Nije postavljeno
-    extended_description_html: |
-      <h3>Dobro mesto za pravila</h3>
-      <p>Prošireni opis koji još nije postavljen.</p>
     generic_description: "%{domain} je server na mreži"
     hosted_on: Mastodont hostovan na %{domain}
     learn_more: Saznajte više
@@ -381,9 +378,6 @@ sr-Latn:
       too_many: Ne može se prikačiti više od 4 fajla
   migrations:
     acct: korisnik@domen novog naloga
-    currently_redirecting: 'Profil Vam je podešen da preusmerava na :'
-    proceed: Sačuvaj
-    updated_msg: Prebacivanje postavki Vašeg naloga uspešno izmenjeno!
   moderation:
     title: Moderacija
   notification_mailer:
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index 772c04d64..4a5d551ef 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -9,9 +9,6 @@ sr:
     contact: Контакт
     contact_missing: Није постављено
     documentation: Документација
-    extended_description_html: |
-      <h3>Добро место за правила</h3>
-      <p>Проширени опис који још није постављен.</p>
     generic_description: "%{domain} је сервер на мрежи"
     hosted_on: Мастодонт хостован на %{domain}
     learn_more: Сазнајте више
@@ -614,9 +611,6 @@ sr:
       too_many: Не може се прикачити више од 4 фајла
   migrations:
     acct: корисник@домен новог налога
-    currently_redirecting: 'Профил Вам је подешен да преусмерава на :'
-    proceed: Сачувај
-    updated_msg: Пребацивање поставки Вашег налога успешно измењено!
   moderation:
     title: Модерација
   notification_mailer:
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index a71ea9e18..740aad00d 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -8,9 +8,6 @@ sv:
     api: API
     contact: Kontakt
     contact_missing: Inte inställd
-    extended_description_html: |
-      <h3>En bra plats för regler</h3>
-      <p>Den utökade beskrivningen har inte konfigurerats ännu.</p>
     generic_description: "%{domain} är en server i nätverket"
     hosted_on: Mastodon värd på %{domain}
     learn_more: Lär dig mer
@@ -454,9 +451,6 @@ sv:
       too_many: Det går inte att bifoga mer än 4 filer
   migrations:
     acct: användarnamn@domän av det nya kontot
-    currently_redirecting: 'Din profil är satt att omdirigeras till:'
-    proceed: Spara
-    updated_msg: Dina kontoflyttsinställning har uppdaterats!
   moderation:
     title: Moderera
   notification_mailer:
diff --git a/config/locales/te.yml b/config/locales/te.yml
index 560a295a6..ec4846554 100644
--- a/config/locales/te.yml
+++ b/config/locales/te.yml
@@ -10,9 +10,6 @@ te:
     contact_missing: ఇంకా సెట్ చేయలేదు
     contact_unavailable: వర్తించదు
     documentation: పత్రీకరణ
-    extended_description_html: |
-      <h3>నియమాలకు ఒక మంచి ప్రదేశం</h3>
-      <p>మరింత విశదీకరణ ఇంకా సెట్ చేయబడలేదు.</p>
     generic_description: "%{domain} అనేది నెట్వర్కులోని ఒక సర్వరు"
     hosted_on: మాస్టొడాన్ %{domain} లో హోస్టు చేయబడింది
     learn_more: మరింత తెలుసుకోండి
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 97ef41460..09d81c752 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -17,9 +17,6 @@ th:
     contact_unavailable: ไม่มี
     discover_users: ค้นพบผู้ใช้
     documentation: เอกสารประกอบ
-    extended_description_html: |
-      <h3>สถานที่ที่ดีสำหรับกฎ</h3>
-      <p>ยังไม่ได้ตั้งคำอธิบายเพิ่มเติม</p>
     federation_hint_html: เมื่อคุณมีบัญชีที่ %{instance} แล้ว คุณสามารถติดตามผู้คนบนเซิร์ฟเวอร์ Mastodon เซิร์ฟเวอร์ใดก็ได้
     generic_description: "%{domain} เป็นเซิร์ฟเวอร์หนึ่งในเครือข่าย"
     get_apps: ลองแอปสำหรับมือถือ
@@ -33,6 +30,8 @@ th:
       other: สถานะ
     status_count_before: ผู้ใช้เหล่านั้นได้สร้าง
     terms: เงื่อนไขการให้บริการ
+    unavailable_content_description:
+      reason: 'เหตุผล:'
     user_count_after:
       other: ผู้ใช้
     user_count_before: บ้านของ
@@ -177,6 +176,7 @@ th:
     custom_emojis:
       by_domain: โดเมน
       copy: คัดลอก
+      create_new_category: สร้างหมวดหมู่ใหม่
       created_msg: สร้างอีโมจิสำเร็จ!
       delete: ลบ
       destroyed_msg: ทำลายอีโมโจสำเร็จ!
@@ -220,6 +220,7 @@ th:
       created_msg: กำลังประมวลผลการปิดกั้นโดเมน
       destroyed_msg: เลิกทำการปิดกั้นโดเมนแล้ว
       domain: โดเมน
+      edit: แก้ไขการปิดกั้นโดเมน
       new:
         create: สร้างการปิดกั้น
         hint: การปิดกั้นโดเมนจะไม่ป้องกันการสร้างรายการบัญชีในฐานข้อมูล แต่จะใช้วิธีการควบคุมเฉพาะกับบัญชีเหล่านั้นย้อนหลังและโดยอัตโนมัติ
@@ -229,6 +230,8 @@ th:
           silence: เงียบ
           suspend: ระงับ
         title: การปิดกั้นโดเมนใหม่
+      private_comment: ความคิดเห็นส่วนตัว
+      public_comment: ความคิดเห็นสาธารณะ
       reject_media: ปฏิเสธไฟล์สื่อ
       reject_media_hint: เอาไฟล์สื่อที่จัดเก็บไว้ในเว็บออกและปฏิเสธที่จะดาวน์โหลดไฟล์ใด ๆ ในอนาคต ไม่เกี่ยวข้องกับการระงับ
       reject_reports: ปฏิเสธรายงาน
@@ -244,6 +247,7 @@ th:
         title: เลิกทำการปิดกั้นโดเมนสำหรับ %{domain}
         undo: เลิกทำ
       undo: เลิกทำการปิดกั้นโดเมน
+      view: ดูการปิดกั้นโดเมน
     email_domain_blocks:
       add_new: เพิ่มใหม่
       delete: ลบ
@@ -351,11 +355,14 @@ th:
         delete: ลบ
         nsfw_off: ทำเครื่องหมายว่าไม่ละเอียดอ่อน
         nsfw_on: ทำเครื่องหมายว่าละเอียดอ่อน
+      deleted: ลบแล้ว
       media:
         title: สื่อ
       no_media: ไม่มีสื่อ
       title: สถานะบัญชี
     tags:
+      in_directory: "%{count} ในไดเรกทอรี"
+      name: แฮชแท็ก
       title: แฮชแท็ก
     title: การดูแล
     warning_presets:
@@ -408,6 +415,9 @@ th:
       return: แสดงโปรไฟล์ของผู้ใช้
       web: ไปยังเว็บ
     title: ติดตาม %{acct}
+  challenge:
+    invalid_password: รหัสผ่านไม่ถูกต้อง
+    prompt: ยืนยันรหัสผ่านเพื่อดำเนินการต่อ
   datetime:
     distance_in_words:
       about_x_hours: "%{count} ชั่วโมง"
@@ -515,7 +525,6 @@ th:
       too_many: ไม่สามารถแนบมากกว่า 4 ไฟล์
   migrations:
     acct: username@domain ของบัญชีใหม่
-    proceed: บันทึก
   moderation:
     title: การควบคุม
   notification_mailer:
@@ -645,6 +654,7 @@ th:
       video:
         other: "%{count} วิดีโอ"
     content_warning: 'คำเตือนเนื้อหา: %{warning}'
+    language_detection: ตรวจหาภาษาโดยอัตโนมัติ
     open_in_web: เปิดในเว็บ
     pin_errors:
       reblog: ไม่สามารถปักหมุดการดัน
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index 550b1cc49..b6817999e 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -17,9 +17,6 @@ tr:
     contact_unavailable: Yok
     discover_users: Kullanıcıları keşfet
     documentation: Belgeler
-    extended_description_html: |
-      <h3>Kural için iyi bir yer</h3>
-      <p>Genişletilmiş açıklama henüz ayarlanmamış.</p>
     federation_hint_html: "%{instance} hesabınızla, herhangi bir Mastodon sunucusundaki ve haricindeki kişileri takip edebilirsiniz."
     generic_description: "%{domain} ağdaki bir sunucudur"
     get_apps: Bir mobil uygulamayı deneyin
@@ -444,14 +441,6 @@ tr:
     directory: Profil dizini
     explanation: Kullanıcıları ilgi alanlarına göre keşfedin
     explore_mastodon: "%{title} keşfet"
-  domain_blocks:
-    blocked_domains: Sınırlı ve engellenen alanların listesi
-    description: Bu, %{instance} öğesinin sınırladığı veya federasyonu reddettiği sunucuların listesidir.
-    domain: Alan adı
-    severity_legend:
-      media_block: Sunucudan gelen medya dosyaları alınmaz, saklanmaz veya kullanıcıya gösterilmez.
-      silence: Susturulmuş sunuculardaki hesaplar bulunabilir, takip edilebilinir ve onlarla etkileşime girilebilinir, ancak gönderileri genel zaman çizelgelerinde görünmez ve onlardan gelen bildirimler onları takip etmeyen yerel kullanıcılara ulaşmaz.
-    show_rationale: Gerekçeyi göster
   domain_validator:
     invalid_domain: geçerli bir alan adı değil
   errors:
@@ -540,10 +529,6 @@ tr:
     validations:
       images_and_video: Halihazırda görsel içeren bir gönderiye video ekleyemezsiniz
       too_many: 4'ten fazla dosya ekleyemezsiniz
-  migrations:
-    currently_redirecting: 'Profiliniz yönlendirmek üzere ayarlandı:'
-    proceed: Kaydet
-    updated_msg: Hesap taşıma ayarınız başarıyla güncellendi!
   moderation:
     title: Yönetim
   notification_mailer:
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index 5edbbd194..ade86d604 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -17,9 +17,6 @@ uk:
     contact_unavailable: Недоступно
     discover_users: Знайдіть цікавих користувачів
     documentation: Документація
-    extended_description_html: |
-      <h3>Гарне місце для правил</h3>
-      <p>Детальний опис ще не налаштований.</p>
     federation_hint_html: З обліковим записом на %{instance} ви зможете слідкувати за людьми на будь-якому сервері Mastodon та поза ним.
     generic_description: "%{domain} є одним сервером у мережі"
     get_apps: Спробуйте мобільний додаток
@@ -651,17 +648,6 @@ uk:
     directory: Каталог профілів
     explanation: Шукайте користувачів за їх інтересами
     explore_mastodon: Досліджуйте %{title}
-  domain_blocks:
-    blocked_domains: Обмежені та заблоковані домени
-    description: Перелік серверів, з якими %{instance} не хоче або не буде вступати до федеративних відносин.
-    domain: Домен
-    no_domain_blocks: "(Немає заблокованих доменів)"
-    severity_legend:
-      media_block: Файли медіа з цього сервера не отримуються, не зберігаються та не відображаються.
-      suspension: Інформація з призупинених серверів не зберігається та не відображається. Ніякі дані не надсилаються до них, взаємодії ігноруються.
-      suspension_disclaimer: Призупинені сервери можуть інколи отримувати публічні дані з цього сервера.
-    show_rationale: Обґрунтування
-    title: "%{instance} Перелік заблокованих серверів"
   domain_validator:
     invalid_domain: не є допустимим ім'ям домену
   errors:
@@ -797,9 +783,6 @@ uk:
       too_many: Не можна додати більше 4 файлів
   migrations:
     acct: username@domain нового облікового запису
-    currently_redirecting: 'Ваш профіль налаштований перенаправляти до:'
-    proceed: Зберегти
-    updated_msg: Налаштування переїзду вашого облікового запису успішно оновлені!
   moderation:
     title: Модерація
   notification_mailer:
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 9c6fd27e8..89506e223 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -17,9 +17,6 @@ zh-CN:
     contact_unavailable: 未公开
     discover_users: 发现用户
     documentation: 文档
-    extended_description_html: |
-      <h3>这里可以写一些规定</h3>
-      <p>本站尚未设置详细介绍。</p>
     federation_hint_html: 在%{instance} 上拥有账户后,你可以关注任何 Mastodon 服务器或其他服务器上的人。
     generic_description: "%{domain} 是这个庞大网络中的一台服务器"
     get_apps: 尝试移动应用
@@ -593,10 +590,6 @@ zh-CN:
     directory: 用户目录
     explanation: 根据兴趣发现用户
     explore_mastodon: 探索 %{title}
-  domain_blocks:
-    silence: 隐藏
-    suspension: 屏蔽
-    title: "%{instance} 已屏蔽实例列表"
   domain_validator:
     invalid_domain: 不是一个有效的域名
   errors:
@@ -730,9 +723,6 @@ zh-CN:
       too_many: 最多只能添加 4 张图片
   migrations:
     acct: 新帐户的 用户名@域名
-    currently_redirecting: 目前你的个人资料页显示的新帐户是:
-    proceed: 保存
-    updated_msg: 帐户迁移设置更新成功!
   moderation:
     title: 运营
   notification_mailer:
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index 2c59b3f07..6f77f52c3 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -8,9 +8,6 @@ zh-HK:
     contact: 聯絡
     contact_missing: 未設定
     contact_unavailable: 未公開
-    extended_description_html: |
-      <h3>這裡可以寫一些網站規則</h3>
-      <p>本站未有詳細介紹</p>
     generic_description: "%{domain} 是 Mastodon 網絡中其中一個服務站"
     hosted_on: 在 %{domain} 運作的 Mastodon 服務站
     learn_more: 了解更多
@@ -465,9 +462,6 @@ zh-HK:
       too_many: 不可以加入超過 4 個檔案
   migrations:
     acct: 新帳戶的 用戶名@域名
-    currently_redirecting: 目前你的個人資料頁顯示的新帳戶是:
-    proceed: 保存
-    updated_msg: 帳戶遷移設置更新成功!
   moderation:
     title: 營運
   notification_mailer:
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index 8bdbf87aa..7750d596b 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -16,9 +16,6 @@ zh-TW:
     contact_unavailable: 未公開
     discover_users: 探索使用者
     documentation: 文件
-    extended_description_html: |
-      <h3>這裡可以寫一些網站規則</h3>
-      <p>本站點未有詳細介紹</p>
     generic_description: "%{domain} 是 Mastodon 網路中其中一個站點"
     get_apps: 嘗試行動應用程式
     hosted_on: 在 %{domain} 運作的 Mastodon 站點
@@ -535,9 +532,6 @@ zh-TW:
       too_many: 無法加入超過 4 個檔案
   migrations:
     acct: 新帳戶的 使用者名稱@站點網域
-    currently_redirecting: 目前你的個人資料頁顯示的新帳戶是:
-    proceed: 儲存
-    updated_msg: 帳戶搬遷設定更新成功!
   moderation:
     title: 營運
   notification_mailer:
diff --git a/config/navigation.rb b/config/navigation.rb
index d6e196ee1..ab4262182 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -5,7 +5,7 @@ SimpleNavigation::Configuration.run do |navigation|
     n.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_url
 
     n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_url, if: -> { current_user.functional? } do |s|
-      s.item :profile, safe_join([fa_icon('pencil fw'), t('settings.appearance')]), settings_profile_url, highlights_on: %r{/settings/profile|/settings/migration}
+      s.item :profile, safe_join([fa_icon('pencil fw'), t('settings.appearance')]), settings_profile_url
       s.item :featured_tags, safe_join([fa_icon('hashtag fw'), t('settings.featured_tags')]), settings_featured_tags_url
       s.item :identity_proofs, safe_join([fa_icon('key fw'), t('settings.identity_proofs')]), settings_identity_proofs_path, highlights_on: %r{/settings/identity_proofs*}, if: proc { current_account.identity_proofs.exists? }
     end
@@ -26,13 +26,13 @@ SimpleNavigation::Configuration.run do |navigation|
     n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? }
 
     n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_url do |s|
-      s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete}
+      s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases}
       s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_url, highlights_on: %r{/settings/two_factor_authentication}
       s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url
     end
 
-    n.item :data, safe_join([fa_icon('cloud-download fw'), t('settings.import_and_export')]), settings_export_url, if: -> { current_user.functional? } do |s|
-      s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_url
+    n.item :data, safe_join([fa_icon('cloud-download fw'), t('settings.import_and_export')]), settings_export_url do |s|
+      s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_url, if: -> { current_user.functional? }
       s.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_url
     end
 
@@ -53,7 +53,7 @@ SimpleNavigation::Configuration.run do |navigation|
       s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_url
       s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/settings}
       s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}
-      s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/relays}
+      s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? && !whitelist_mode? }, highlights_on: %r{/admin/relays}
       s.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? }
       s.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? }
     end
diff --git a/config/routes.rb b/config/routes.rb
index 416bd833e..49edb4602 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -24,10 +24,13 @@ Rails.application.routes.draw do
   end
 
   get '.well-known/host-meta', to: 'well_known/host_meta#show', as: :host_meta, defaults: { format: 'xml' }
+  get '.well-known/nodeinfo', to: 'well_known/nodeinfo#index', as: :nodeinfo, defaults: { format: 'json' }
   get '.well-known/webfinger', to: 'well_known/webfinger#show', as: :webfinger
   get '.well-known/change-password', to: redirect('/auth/edit')
   get '.well-known/keybase-proof-config', to: 'well_known/keybase_proof_config#show'
 
+  get '/nodeinfo/2.0', to: 'well_known/nodeinfo#show', as: :nodeinfo_schema
+
   get 'manifest', to: 'manifests#show', defaults: { format: 'json' }
   get 'intent', to: 'intents#show'
   get 'custom.css', to: 'custom_css#show', as: :custom_css
@@ -41,6 +44,7 @@ Rails.application.routes.draw do
 
     namespace :auth do
       resource :setup, only: [:show, :update], controller: :setup
+      resource :challenge, only: [:create], controller: :challenges
     end
   end
 
@@ -135,8 +139,13 @@ Rails.application.routes.draw do
     resources :flavours, only: [:index, :show, :update], param: :flavour
 
     resource :delete, only: [:show, :destroy]
-    resource :migration, only: [:show, :update]
+    resource :migration, only: [:show, :create]
+
+    namespace :migration do
+      resource :redirect, only: [:new, :create, :destroy]
+    end
 
+    resources :aliases, only: [:index, :create, :destroy]
     resources :sessions, only: [:destroy]
     resources :featured_tags, only: [:index, :create, :destroy]
   end
@@ -452,7 +461,6 @@ Rails.application.routes.draw do
 
   get '/about',        to: 'about#show'
   get '/about/more',   to: 'about#more'
-  get '/about/blocks', to: 'about#blocks'
   get '/terms',        to: 'about#terms'
 
   match '/', via: [:post, :put, :patch, :delete], to: 'application#raise_not_found', format: false
diff --git a/db/migrate/20161202132159_add_in_reply_to_account_id_to_statuses.rb b/db/migrate/20161202132159_add_in_reply_to_account_id_to_statuses.rb
index 2c24b53d0..3a559ccd6 100644
--- a/db/migrate/20161202132159_add_in_reply_to_account_id_to_statuses.rb
+++ b/db/migrate/20161202132159_add_in_reply_to_account_id_to_statuses.rb
@@ -3,7 +3,7 @@ class AddInReplyToAccountIdToStatuses < ActiveRecord::Migration[5.0]
     add_column :statuses, :in_reply_to_account_id, :integer, null: true, default: nil
 
     ActiveRecord::Base.transaction do
-      Status.where.not(in_reply_to_id: nil).includes(:thread).find_each do |status|
+      Status.unscoped.where.not(in_reply_to_id: nil).includes(:thread).find_each do |status|
         next if status.thread.nil?
 
         status.in_reply_to_account_id = status.thread.account_id
diff --git a/db/migrate/20170209184350_add_reply_to_statuses.rb b/db/migrate/20170209184350_add_reply_to_statuses.rb
index c5074728b..b8b5c1306 100644
--- a/db/migrate/20170209184350_add_reply_to_statuses.rb
+++ b/db/migrate/20170209184350_add_reply_to_statuses.rb
@@ -1,7 +1,7 @@
 class AddReplyToStatuses < ActiveRecord::Migration[5.0]
   def up
     add_column :statuses, :reply, :boolean, nil: false, default: false
-    Status.update_all('reply = (in_reply_to_id IS NOT NULL)')
+    Status.unscoped.update_all('reply = (in_reply_to_id IS NOT NULL)')
   end
 
   def down
diff --git a/db/migrate/20190914202517_create_account_migrations.rb b/db/migrate/20190914202517_create_account_migrations.rb
new file mode 100644
index 000000000..cb9d71c09
--- /dev/null
+++ b/db/migrate/20190914202517_create_account_migrations.rb
@@ -0,0 +1,12 @@
+class CreateAccountMigrations < ActiveRecord::Migration[5.2]
+  def change
+    create_table :account_migrations do |t|
+      t.belongs_to :account, foreign_key: { on_delete: :cascade }
+      t.string :acct, null: false, default: ''
+      t.bigint :followers_count, null: false, default: 0
+      t.belongs_to :target_account, foreign_key: { to_table: :accounts, on_delete: :nullify }
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20190915194355_create_account_aliases.rb b/db/migrate/20190915194355_create_account_aliases.rb
new file mode 100644
index 000000000..32ce031d9
--- /dev/null
+++ b/db/migrate/20190915194355_create_account_aliases.rb
@@ -0,0 +1,11 @@
+class CreateAccountAliases < ActiveRecord::Migration[5.2]
+  def change
+    create_table :account_aliases do |t|
+      t.belongs_to :account, foreign_key: { on_delete: :cascade }
+      t.string :acct, null: false, default: ''
+      t.string :uri, null: false, default: ''
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20190927232842_add_voters_count_to_polls.rb b/db/migrate/20190927232842_add_voters_count_to_polls.rb
new file mode 100644
index 000000000..846385700
--- /dev/null
+++ b/db/migrate/20190927232842_add_voters_count_to_polls.rb
@@ -0,0 +1,5 @@
+class AddVotersCountToPolls < ActiveRecord::Migration[5.2]
+  def change
+    add_column :polls, :voters_count, :bigint
+  end
+end
diff --git a/db/post_migrate/20190927124642_remove_invalid_web_push_subscription.rb b/db/post_migrate/20190927124642_remove_invalid_web_push_subscription.rb
new file mode 100644
index 000000000..c2397476a
--- /dev/null
+++ b/db/post_migrate/20190927124642_remove_invalid_web_push_subscription.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class RemoveInvalidWebPushSubscription < ActiveRecord::Migration[5.2]
+  disable_ddl_transaction!
+
+  def up
+    invalid_web_push_subscriptions = Web::PushSubscription.where(endpoint: '')
+                                                          .or(Web::PushSubscription.where(key_p256dh: ''))
+                                                          .or(Web::PushSubscription.where(key_auth: ''))
+                                                          .preload(:session_activation)
+    invalid_web_push_subscriptions.find_each do |web_push_subscription|
+      web_push_subscription.session_activation&.update!(web_push_subscription_id: nil)
+      web_push_subscription.destroy!
+    end
+  end
+
+  def down; end
+end
diff --git a/db/schema.rb b/db/schema.rb
index c4b25d991..6e2f6a2e7 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,11 +10,20 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2019_09_17_213523) do
+ActiveRecord::Schema.define(version: 2019_09_27_232842) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
 
+  create_table "account_aliases", force: :cascade do |t|
+    t.bigint "account_id"
+    t.string "acct", default: "", null: false
+    t.string "uri", default: "", null: false
+    t.datetime "created_at", null: false
+    t.datetime "updated_at", null: false
+    t.index ["account_id"], name: "index_account_aliases_on_account_id"
+  end
+
   create_table "account_conversations", force: :cascade do |t|
     t.bigint "account_id"
     t.bigint "conversation_id"
@@ -49,6 +58,17 @@ ActiveRecord::Schema.define(version: 2019_09_17_213523) do
     t.index ["account_id"], name: "index_account_identity_proofs_on_account_id"
   end
 
+  create_table "account_migrations", force: :cascade do |t|
+    t.bigint "account_id"
+    t.string "acct", default: "", null: false
+    t.bigint "followers_count", default: 0, null: false
+    t.bigint "target_account_id"
+    t.datetime "created_at", null: false
+    t.datetime "updated_at", null: false
+    t.index ["account_id"], name: "index_account_migrations_on_account_id"
+    t.index ["target_account_id"], name: "index_account_migrations_on_target_account_id"
+  end
+
   create_table "account_moderation_notes", force: :cascade do |t|
     t.text "content", null: false
     t.bigint "account_id", null: false
@@ -520,6 +540,7 @@ ActiveRecord::Schema.define(version: 2019_09_17_213523) do
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
     t.integer "lock_version", default: 0, null: false
+    t.bigint "voters_count"
     t.index ["account_id"], name: "index_polls_on_account_id"
     t.index ["status_id"], name: "index_polls_on_status_id"
   end
@@ -781,10 +802,13 @@ ActiveRecord::Schema.define(version: 2019_09_17_213523) do
     t.index ["user_id"], name: "index_web_settings_on_user_id", unique: true
   end
 
+  add_foreign_key "account_aliases", "accounts", on_delete: :cascade
   add_foreign_key "account_conversations", "accounts", on_delete: :cascade
   add_foreign_key "account_conversations", "conversations", on_delete: :cascade
   add_foreign_key "account_domain_blocks", "accounts", name: "fk_206c6029bd", on_delete: :cascade
   add_foreign_key "account_identity_proofs", "accounts", on_delete: :cascade
+  add_foreign_key "account_migrations", "accounts", column: "target_account_id", on_delete: :nullify
+  add_foreign_key "account_migrations", "accounts", on_delete: :cascade
   add_foreign_key "account_moderation_notes", "accounts"
   add_foreign_key "account_moderation_notes", "accounts", column: "target_account_id"
   add_foreign_key "account_pins", "accounts", column: "target_account_id", on_delete: :cascade
diff --git a/lib/devise/ldap_authenticatable.rb b/lib/devise/ldap_authenticatable.rb
deleted file mode 100644
index 6903d468d..000000000
--- a/lib/devise/ldap_authenticatable.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# frozen_string_literal: true
-
-require 'net/ldap'
-require 'devise/strategies/authenticatable'
-
-module Devise
-  module Strategies
-    class LdapAuthenticatable < Authenticatable
-      def authenticate!
-        if params[:user]
-          ldap = Net::LDAP.new(
-            host: Devise.ldap_host,
-            port: Devise.ldap_port,
-            base: Devise.ldap_base,
-            encryption: {
-              method: Devise.ldap_method,
-              tls_options: tls_options,
-            },
-            auth: {
-              method: :simple,
-              username: Devise.ldap_bind_dn,
-              password: Devise.ldap_password,
-            },
-            connect_timeout: 10
-          )
-
-          filter = format(Devise.ldap_search_filter, uid: Devise.ldap_uid, email: email)
-
-          if (user_info = ldap.bind_as(base: Devise.ldap_base, filter: filter, password: password))
-            user = User.ldap_get_user(user_info.first)
-            success!(user)
-          else
-            return fail(:invalid)
-          end
-        end
-      end
-
-      def email
-        params[:user][:email]
-      end
-
-      def password
-        params[:user][:password]
-      end
-
-      def tls_options
-        OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.tap do |options|
-          options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if Devise.ldap_tls_no_verify
-        end
-      end
-    end
-  end
-end
-
-Warden::Strategies.add(:ldap_authenticatable, Devise::Strategies::LdapAuthenticatable)
diff --git a/lib/devise/two_factor_ldap_authenticatable.rb b/lib/devise/two_factor_ldap_authenticatable.rb
new file mode 100644
index 000000000..065aa2de8
--- /dev/null
+++ b/lib/devise/two_factor_ldap_authenticatable.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'net/ldap'
+require 'devise/strategies/base'
+
+module Devise
+  module Strategies
+    class TwoFactorLdapAuthenticatable < Base
+      def valid?
+        valid_params? && mapping.to.respond_to?(:authenticate_with_ldap)
+      end
+
+      def authenticate!
+        resource = mapping.to.authenticate_with_ldap(params[scope])
+
+        if resource && !resource.otp_required_for_login?
+          success!(resource)
+        else
+          fail(:invalid)
+        end
+      end
+
+      protected
+
+      def valid_params?
+        params[scope] && params[scope][:password].present?
+      end
+    end
+  end
+end
+
+Warden::Strategies.add(:two_factor_ldap_authenticatable, Devise::Strategies::TwoFactorLdapAuthenticatable)
diff --git a/lib/devise/two_factor_pam_authenticatable.rb b/lib/devise/two_factor_pam_authenticatable.rb
new file mode 100644
index 000000000..5ce723b33
--- /dev/null
+++ b/lib/devise/two_factor_pam_authenticatable.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'devise/strategies/base'
+
+module Devise
+  module Strategies
+    class TwoFactorPamAuthenticatable < Base
+      def valid?
+        valid_params? && mapping.to.respond_to?(:authenticate_with_pam)
+      end
+
+      def authenticate!
+        resource = mapping.to.authenticate_with_pam(params[scope])
+
+        if resource && !resource.otp_required_for_login?
+          success!(resource)
+        else
+          fail(:invalid)
+        end
+      end
+
+      protected
+
+      def valid_params?
+        params[scope] && params[scope][:password].present?
+      end
+    end
+  end
+end
+
+Warden::Strategies.add(:two_factor_pam_authenticatable, Devise::Strategies::TwoFactorPamAuthenticatable)
diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb
index 4645feb2f..38cae8766 100644
--- a/lib/mastodon/version.rb
+++ b/lib/mastodon/version.rb
@@ -5,19 +5,19 @@ module Mastodon
     module_function
 
     def major
-      2
+      3
     end
 
     def minor
-      9
+      0
     end
 
     def patch
-      2
+      0
     end
 
     def flags
-      ''
+      'rc2'
     end
 
     def suffix
diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake
index ee9657b0e..2e92e8ded 100644
--- a/lib/tasks/mastodon.rake
+++ b/lib/tasks/mastodon.rake
@@ -135,7 +135,7 @@ namespace :mastodon do
       prompt.say "\n"
 
       if prompt.yes?('Do you want to store uploaded files on the cloud?', default: false)
-        case prompt.select('Provider', ['Amazon S3', 'Wasabi', 'Minio'])
+        case prompt.select('Provider', ['Amazon S3', 'Wasabi', 'Minio', 'Google Cloud Storage'])
         when 'Amazon S3'
           env['S3_ENABLED']  = 'true'
           env['S3_PROTOCOL'] = 'https'
@@ -217,6 +217,34 @@ namespace :mastodon do
             q.required true
             q.modify :strip
           end
+        when 'Google Cloud Storage'
+          env['S3_ENABLED']             = 'true'
+          env['S3_PROTOCOL']            = 'https'
+          env['S3_HOSTNAME']            = 'storage.googleapis.com'
+          env['S3_ENDPOINT']            = 'https://storage.googleapis.com'
+          env['S3_MULTIPART_THRESHOLD'] = 50.megabytes
+
+          env['S3_BUCKET'] = prompt.ask('GCS bucket name:') do |q|
+            q.required true
+            q.default "files.#{env['LOCAL_DOMAIN']}"
+            q.modify :strip
+          end
+
+          env['S3_REGION'] = prompt.ask('GCS region:') do |q|
+            q.required true
+            q.default 'us-west1'
+            q.modify :strip
+          end
+
+          env['AWS_ACCESS_KEY_ID'] = prompt.ask('GCS access key:') do |q|
+            q.required true
+            q.modify :strip
+          end
+
+          env['AWS_SECRET_ACCESS_KEY'] = prompt.ask('GCS secret key:') do |q|
+            q.required true
+            q.modify :strip
+          end
         end
 
         if prompt.yes?('Do you want to access the uploaded files from your own domain?')
diff --git a/package.json b/package.json
index 97d3ec497..6282f1439 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
 {
-  "name": "mastodon",
+  "name": "@tootsuite/mastodon",
   "license": "AGPL-3.0-or-later",
   "engines": {
     "node": ">=8.12 <13"
@@ -114,7 +114,7 @@
     "lodash": "^4.17.14",
     "mark-loader": "^0.1.6",
     "marky": "^1.2.1",
-    "mini-css-extract-plugin": "^0.7.0",
+    "mini-css-extract-plugin": "^0.8.0",
     "mkdirp": "^0.5.1",
     "npmlog": "^4.1.2",
     "object-assign": "^4.1.1",
@@ -155,7 +155,7 @@
     "requestidlecallback": "^0.3.0",
     "reselect": "^4.0.0",
     "rimraf": "^3.0.0",
-    "sass": "^1.22.9",
+    "sass": "^1.22.12",
     "sass-loader": "^7.0.3",
     "stringz": "^2.0.0",
     "substring-trie": "^1.0.2",
@@ -174,10 +174,10 @@
   },
   "devDependencies": {
     "babel-eslint": "^10.0.3",
-    "babel-jest": "^24.8.0",
+    "babel-jest": "^24.9.0",
     "enzyme": "^3.10.0",
     "enzyme-adapter-react-16": "^1.14.0",
-    "eslint": "^6.1.0",
+    "eslint": "^6.4.0",
     "eslint-plugin-import": "~2.18.2",
     "eslint-plugin-jsx-a11y": "~6.2.3",
     "eslint-plugin-promise": "~4.2.1",
diff --git a/scalingo.json b/scalingo.json
index dd8fb5530..324356df0 100644
--- a/scalingo.json
+++ b/scalingo.json
@@ -8,15 +8,6 @@
       "description": "The domain that your Mastodon instance will run on (this can be appname.scalingo.io or a custom domain)",
       "required": true
     },
-    "LOCAL_HTTPS": {
-      "description": "Will your domain support HTTPS? (Automatic for *.scalingo.io, requires manual configuration for custom domains)",
-      "value": "true",
-      "required": true
-    },
-    "PAPERCLIP_SECRET": {
-      "description": "The secret key for storing media files",
-      "generator": "secret"
-    },
     "SECRET_KEY_BASE": {
       "description": "The secret key base",
       "generator": "secret"
diff --git a/spec/controllers/auth/challenges_controller_spec.rb b/spec/controllers/auth/challenges_controller_spec.rb
new file mode 100644
index 000000000..2a6ca301e
--- /dev/null
+++ b/spec/controllers/auth/challenges_controller_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Auth::ChallengesController, type: :controller do
+  render_views
+
+  let(:password) { 'foobar12345' }
+  let(:user) { Fabricate(:user, password: password) }
+
+  before do
+    sign_in user
+  end
+
+  describe 'POST #create' do
+    let(:return_to) { edit_user_registration_path }
+
+    context 'with correct password' do
+      before { post :create, params: { form_challenge: { return_to: return_to, current_password: password } } }
+
+      it 'redirects back' do
+        expect(response).to redirect_to(return_to)
+      end
+
+      it 'sets session' do
+        expect(session[:challenge_passed_at]).to_not be_nil
+      end
+    end
+
+    context 'with incorrect password' do
+      before { post :create, params: { form_challenge: { return_to: return_to, current_password: 'hhfggjjd562' } } }
+
+      it 'renders challenge' do
+        expect(response).to render_template('auth/challenges/new')
+      end
+
+      it 'displays error' do
+        expect(response.body).to include 'Invalid password'
+      end
+
+      it 'does not set session' do
+        expect(session[:challenge_passed_at]).to be_nil
+      end
+    end
+  end
+end
diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb
index 7ed5edde0..1950c173a 100644
--- a/spec/controllers/auth/sessions_controller_spec.rb
+++ b/spec/controllers/auth/sessions_controller_spec.rb
@@ -80,7 +80,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
         let(:user) do
           account = Fabricate.build(:account, username: 'pam_user1')
           account.save!(validate: false)
-          user = Fabricate(:user, email: 'pam@example.com', password: nil, account: account)
+          user = Fabricate(:user, email: 'pam@example.com', password: nil, account: account, external: true)
           user
         end
 
diff --git a/spec/controllers/concerns/challengable_concern_spec.rb b/spec/controllers/concerns/challengable_concern_spec.rb
new file mode 100644
index 000000000..4db3b740d
--- /dev/null
+++ b/spec/controllers/concerns/challengable_concern_spec.rb
@@ -0,0 +1,114 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe ChallengableConcern, type: :controller do
+  controller(ApplicationController) do
+    include ChallengableConcern
+
+    before_action :require_challenge!
+
+    def foo
+      render plain: 'foo'
+    end
+
+    def bar
+      render plain: 'bar'
+    end
+  end
+
+  before do
+    routes.draw do
+      get  'foo' => 'anonymous#foo'
+      post 'bar' => 'anonymous#bar'
+    end
+  end
+
+  context 'with a no-password user' do
+    let(:user) { Fabricate(:user, external: true, password: nil) }
+
+    before do
+      sign_in user
+    end
+
+    context 'for GET requests' do
+      before { get :foo }
+
+      it 'does not ask for password' do
+        expect(response.body).to eq 'foo'
+      end
+    end
+
+    context 'for POST requests' do
+      before { post :bar }
+
+      it 'does not ask for password' do
+        expect(response.body).to eq 'bar'
+      end
+    end
+  end
+
+  context 'with recent challenge in session' do
+    let(:password) { 'foobar12345' }
+    let(:user) { Fabricate(:user, password: password) }
+
+    before do
+      sign_in user
+    end
+
+    context 'for GET requests' do
+      before { get :foo, session: { challenge_passed_at: Time.now.utc } }
+
+      it 'does not ask for password' do
+        expect(response.body).to eq 'foo'
+      end
+    end
+
+    context 'for POST requests' do
+      before { post :bar, session: { challenge_passed_at: Time.now.utc } }
+
+      it 'does not ask for password' do
+        expect(response.body).to eq 'bar'
+      end
+    end
+  end
+
+  context 'with a password user' do
+    let(:password) { 'foobar12345' }
+    let(:user) { Fabricate(:user, password: password) }
+
+    before do
+      sign_in user
+    end
+
+    context 'for GET requests' do
+      before { get :foo }
+
+      it 'renders challenge' do
+        expect(response).to render_template('auth/challenges/new')
+      end
+
+      # See Auth::ChallengesControllerSpec
+    end
+
+    context 'for POST requests' do
+      before { post :bar }
+
+      it 'renders challenge' do
+        expect(response).to render_template('auth/challenges/new')
+      end
+
+      it 'accepts correct password' do
+        post :bar, params: { form_challenge: { current_password: password } }
+        expect(response.body).to eq 'bar'
+        expect(session[:challenge_passed_at]).to_not be_nil
+      end
+
+      it 'rejects wrong password' do
+        post :bar, params: { form_challenge: { current_password: 'dddfff888123' } }
+        expect(response.body).to render_template('auth/challenges/new')
+        expect(session[:challenge_passed_at]).to be_nil
+      end
+    end
+  end
+end
diff --git a/spec/controllers/settings/migrations_controller_spec.rb b/spec/controllers/settings/migrations_controller_spec.rb
index 4d814a45e..36e4ba86e 100644
--- a/spec/controllers/settings/migrations_controller_spec.rb
+++ b/spec/controllers/settings/migrations_controller_spec.rb
@@ -21,6 +21,7 @@ describe Settings::MigrationsController do
 
       let(:user) { Fabricate(:user, account: account) }
       let(:account) { Fabricate(:account, moved_to_account: moved_to_account) }
+
       before { sign_in user, scope: :user }
 
       context 'when user does not have moved to account' do
@@ -32,7 +33,7 @@ describe Settings::MigrationsController do
         end
       end
 
-      context 'when user does not have moved to account' do
+      context 'when user has a moved to account' do
         let(:moved_to_account) { Fabricate(:account) }
 
         it 'renders show page' do
@@ -43,21 +44,22 @@ describe Settings::MigrationsController do
     end
   end
 
-  describe 'PUT #update' do
+  describe 'POST #create' do
     context 'when user is not sign in' do
-      subject { put :update }
+      subject { post :create }
 
       it_behaves_like 'authenticate user'
     end
 
     context 'when user is sign in' do
-      subject { put :update, params: { migration: { acct: acct } } }
+      subject { post :create, params: { account_migration: { acct: acct, current_password: '12345678' } } }
+
+      let(:user) { Fabricate(:user, password: '12345678') }
 
-      let(:user) { Fabricate(:user) }
       before { sign_in user, scope: :user }
 
       context 'when migration account is changed' do
-        let(:acct) { Fabricate(:account) }
+        let(:acct) { Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) }
 
         it 'updates moved to account' do
           is_expected.to redirect_to settings_migration_path
diff --git a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb
index 2e5a9325c..336f13127 100644
--- a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb
+++ b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb
@@ -24,7 +24,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
     context 'when signed in' do
       subject do
         sign_in user, scope: :user
-        get :new
+        get :new, session: { challenge_passed_at: Time.now.utc }
       end
 
       include_examples 'renders :new'
@@ -37,7 +37,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
 
     it 'redirects if user do not have otp_secret' do
       sign_in user_without_otp_secret, scope: :user
-      get :new
+      get :new, session: { challenge_passed_at: Time.now.utc }
       expect(response).to redirect_to('/settings/two_factor_authentication')
     end
   end
@@ -50,7 +50,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
 
       describe 'when form_two_factor_confirmation parameter is not provided' do
         it 'raises ActionController::ParameterMissing' do
-          post :create, params: {}
+          post :create, params: {}, session: { challenge_passed_at: Time.now.utc }
           expect(response).to have_http_status(400)
         end
       end
@@ -68,7 +68,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
             true
           end
 
-          post :create, params: { form_two_factor_confirmation: { otp_attempt: '123456' } }
+          post :create, params: { form_two_factor_confirmation: { otp_attempt: '123456' } }, session: { challenge_passed_at: Time.now.utc }
 
           expect(assigns(:recovery_codes)).to eq otp_backup_codes
           expect(flash[:notice]).to eq 'Two-factor authentication successfully enabled'
@@ -85,7 +85,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
             false
           end
 
-          post :create, params: { form_two_factor_confirmation: { otp_attempt: '123456' } }
+          post :create, params: { form_two_factor_confirmation: { otp_attempt: '123456' } }, session: { challenge_passed_at: Time.now.utc }
         end
 
         it 'renders the new view' do
diff --git a/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb
index c04760e53..630cec428 100644
--- a/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb
+++ b/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb
@@ -15,7 +15,7 @@ describe Settings::TwoFactorAuthentication::RecoveryCodesController do
       end
 
       sign_in user, scope: :user
-      post :create
+      post :create, session: { challenge_passed_at: Time.now.utc }
 
       expect(assigns(:recovery_codes)).to eq otp_backup_codes
       expect(flash[:notice]).to eq 'Recovery codes successfully regenerated'
diff --git a/spec/controllers/settings/two_factor_authentications_controller_spec.rb b/spec/controllers/settings/two_factor_authentications_controller_spec.rb
index 922231ded..9df9763fd 100644
--- a/spec/controllers/settings/two_factor_authentications_controller_spec.rb
+++ b/spec/controllers/settings/two_factor_authentications_controller_spec.rb
@@ -58,7 +58,7 @@ describe Settings::TwoFactorAuthenticationsController do
       describe 'when creation succeeds' do
         it 'updates user secret' do
           before = user.otp_secret
-          post :create
+          post :create, session: { challenge_passed_at: Time.now.utc }
 
           expect(user.reload.otp_secret).not_to eq(before)
           expect(response).to redirect_to(new_settings_two_factor_authentication_confirmation_path)
diff --git a/spec/controllers/well_known/nodeinfo_controller_spec.rb b/spec/controllers/well_known/nodeinfo_controller_spec.rb
new file mode 100644
index 000000000..12e1fa415
--- /dev/null
+++ b/spec/controllers/well_known/nodeinfo_controller_spec.rb
@@ -0,0 +1,36 @@
+require 'rails_helper'
+
+describe WellKnown::NodeInfoController, type: :controller do
+  render_views
+
+  describe 'GET #index' do
+    it 'returns json document pointing to node info' do
+      get :index
+
+      expect(response).to have_http_status(200)
+      expect(response.content_type).to eq 'application/json'
+
+      json = body_as_json
+
+      expect(json[:links]).to be_an Array
+      expect(json[:links][0][:rel]).to eq 'http://nodeinfo.diaspora.software/ns/schema/2.0'
+      expect(json[:links][0][:href]).to include 'nodeinfo/2.0'
+    end
+  end
+
+  describe 'GET #show' do
+    it 'returns json document with node info properties' do
+      get :show
+
+      expect(response).to have_http_status(200)
+      expect(response.content_type).to eq 'application/json'
+
+      json = body_as_json
+
+      expect(json[:version]).to eq '2.0'
+      expect(json[:usage]).to be_a Hash
+      expect(json[:software]).to be_a Hash
+      expect(json[:protocols]).to be_an Array
+    end
+  end
+end
diff --git a/spec/fabricators/account_alias_fabricator.rb b/spec/fabricators/account_alias_fabricator.rb
new file mode 100644
index 000000000..94dde9bb8
--- /dev/null
+++ b/spec/fabricators/account_alias_fabricator.rb
@@ -0,0 +1,5 @@
+Fabricator(:account_alias) do
+  account
+  acct 'test@example.com'
+  uri 'https://example.com/users/test'
+end
diff --git a/spec/fabricators/account_migration_fabricator.rb b/spec/fabricators/account_migration_fabricator.rb
new file mode 100644
index 000000000..3b3fc2077
--- /dev/null
+++ b/spec/fabricators/account_migration_fabricator.rb
@@ -0,0 +1,6 @@
+Fabricator(:account_migration) do
+  account
+  target_account
+  followers_count 1234
+  acct 'test@example.com'
+end
diff --git a/spec/lib/activitypub/activity/follow_spec.rb b/spec/lib/activitypub/activity/follow_spec.rb
index 6bbacdbe6..05112cc18 100644
--- a/spec/lib/activitypub/activity/follow_spec.rb
+++ b/spec/lib/activitypub/activity/follow_spec.rb
@@ -31,6 +31,36 @@ RSpec.describe ActivityPub::Activity::Follow do
       end
     end
 
+    context 'silenced account following an unlocked account' do
+      before do
+        sender.touch(:silenced_at)
+        subject.perform
+      end
+
+      it 'does not create a follow from sender to recipient' do
+        expect(sender.following?(recipient)).to be false
+      end
+
+      it 'creates a follow request' do
+        expect(sender.requested?(recipient)).to be true
+      end
+    end
+
+    context 'unlocked account muting the sender' do
+      before do
+        recipient.mute!(sender)
+        subject.perform
+      end
+
+      it 'creates a follow from sender to recipient' do
+        expect(sender.following?(recipient)).to be true
+      end
+
+      it 'does not create a follow request' do
+        expect(sender.requested?(recipient)).to be false
+      end
+    end
+
     context 'locked account' do
       before do
         recipient.update(locked: true)
diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb
index ead3b3baa..464f177d0 100644
--- a/spec/mailers/previews/user_mailer_preview.rb
+++ b/spec/mailers/previews/user_mailer_preview.rb
@@ -18,6 +18,21 @@ class UserMailerPreview < ActionMailer::Preview
     UserMailer.password_change(User.first)
   end
 
+  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/two_factor_disabled
+  def two_factor_disabled
+    UserMailer.two_factor_disabled(User.first)
+  end
+
+  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/two_factor_enabled
+  def two_factor_enabled
+    UserMailer.two_factor_enabled(User.first)
+  end
+
+  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/two_factor_recovery_codes_changed
+  def two_factor_recovery_codes_changed
+    UserMailer.two_factor_recovery_codes_changed(User.first)
+  end
+
   # Preview this email at http://localhost:3000/rails/mailers/user_mailer/reconfirmation_instructions
   def reconfirmation_instructions
     user = User.first
diff --git a/spec/models/account_alias_spec.rb b/spec/models/account_alias_spec.rb
new file mode 100644
index 000000000..27ec215aa
--- /dev/null
+++ b/spec/models/account_alias_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe AccountAlias, type: :model do
+
+end
diff --git a/spec/models/account_migration_spec.rb b/spec/models/account_migration_spec.rb
new file mode 100644
index 000000000..8461b4b28
--- /dev/null
+++ b/spec/models/account_migration_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe AccountMigration, type: :model do
+
+end
diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb
index 86c85293e..ae863a9f0 100644
--- a/spec/services/follow_service_spec.rb
+++ b/spec/services/follow_service_spec.rb
@@ -30,6 +30,33 @@ RSpec.describe FollowService, type: :service do
       end
     end
 
+    describe 'unlocked account, from silenced account' do
+      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+
+      before do
+        sender.touch(:silenced_at)
+        subject.call(sender, bob.acct)
+      end
+
+      it 'creates a follow request with reblogs' do
+        expect(FollowRequest.find_by(account: sender, target_account: bob, show_reblogs: true)).to_not be_nil
+      end
+    end
+
+    describe 'unlocked account, from a muted account' do
+      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+
+      before do
+        bob.mute!(sender)
+        subject.call(sender, bob.acct)
+      end
+
+      it 'creates a following relation with reblogs' do
+        expect(sender.following?(bob)).to be true
+        expect(sender.muting_reblogs?(bob)).to be false
+      end
+    end
+
     describe 'unlocked account' do
       let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
 
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index ade306ed2..739bb9cf5 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -77,10 +77,10 @@ describe SearchService, type: :service do
         it 'includes the tag in the results' do
           query = '#tag'
           tag = Tag.new
-          allow(Tag).to receive(:search_for).with('tag', 10, 0).and_return([tag])
+          allow(Tag).to receive(:search_for).with('tag', 10, 0, exclude_unreviewed: nil).and_return([tag])
 
           results = subject.call(query, nil, 10)
-          expect(Tag).to have_received(:search_for).with('tag', 10, 0)
+          expect(Tag).to have_received(:search_for).with('tag', 10, 0, exclude_unreviewed: nil)
           expect(results).to eq empty_results.merge(hashtags: [tag])
         end
         it 'does not include tag when starts with @ character' do
diff --git a/spec/services/update_account_service_spec.rb b/spec/services/update_account_service_spec.rb
new file mode 100644
index 000000000..960b26891
--- /dev/null
+++ b/spec/services/update_account_service_spec.rb
@@ -0,0 +1,38 @@
+require 'rails_helper'
+
+RSpec.describe UpdateAccountService, type: :service do
+  subject { UpdateAccountService.new }
+
+  describe 'switching form locked to unlocked accounts' do
+    let(:account) { Fabricate(:account, locked: true) }
+    let(:alice)   { Fabricate(:user, email: 'alice@example.com', account: Fabricate(:account, username: 'alice')).account }
+    let(:bob)     { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+    let(:eve)     { Fabricate(:user, email: 'eve@example.com', account: Fabricate(:account, username: 'eve')).account }
+
+    before do
+      bob.touch(:silenced_at)
+      account.mute!(eve)
+
+      FollowService.new.call(alice, account)
+      FollowService.new.call(bob, account)
+      FollowService.new.call(eve, account)
+
+      subject.call(account, { locked: false })
+    end
+
+    it 'auto-accepts pending follow requests' do
+      expect(alice.following?(account)).to be true
+      expect(alice.requested?(account)).to be false
+    end
+
+    it 'does not auto-accept pending follow requests from silenced users' do
+      expect(bob.following?(account)).to be false
+      expect(bob.requested?(account)).to be true
+    end
+
+    it 'auto-accepts pending follow requests from muted users so as to not leak mute' do
+      expect(eve.following?(account)).to be true
+      expect(eve.requested?(account)).to be false
+    end
+  end
+end
diff --git a/yarn.lock b/yarn.lock
index 7811058c0..a31d1bd64 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -953,15 +953,6 @@
     "@jest/types" "^24.9.0"
     jest-mock "^24.9.0"
 
-"@jest/fake-timers@^24.8.0":
-  version "24.8.0"
-  resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.8.0.tgz#2e5b80a4f78f284bcb4bd5714b8e10dd36a8d3d1"
-  integrity sha512-2M4d5MufVXwi6VzZhJ9f5S/wU4ud2ck0kxPof1Iz3zWx6Y+V2eJrES9jEktB6O3o/oEyk+il/uNu9PvASjWXQw==
-  dependencies:
-    "@jest/types" "^24.8.0"
-    jest-message-util "^24.8.0"
-    jest-mock "^24.8.0"
-
 "@jest/fake-timers@^24.9.0":
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93"
@@ -1016,15 +1007,6 @@
     graceful-fs "^4.1.15"
     source-map "^0.6.0"
 
-"@jest/test-result@^24.8.0":
-  version "24.8.0"
-  resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.8.0.tgz#7675d0aaf9d2484caa65e048d9b467d160f8e9d3"
-  integrity sha512-+YdLlxwizlfqkFDh7Mc7ONPQAhA4YylU1s529vVM1rsf67vGZH/2GGm5uO8QzPeVyaVMobCQ7FTxl38QrKRlng==
-  dependencies:
-    "@jest/console" "^24.7.1"
-    "@jest/types" "^24.8.0"
-    "@types/istanbul-lib-coverage" "^2.0.0"
-
 "@jest/test-result@^24.9.0":
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca"
@@ -1044,27 +1026,6 @@
     jest-runner "^24.9.0"
     jest-runtime "^24.9.0"
 
-"@jest/transform@^24.8.0":
-  version "24.8.0"
-  resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.8.0.tgz#628fb99dce4f9d254c6fd9341e3eea262e06fef5"
-  integrity sha512-xBMfFUP7TortCs0O+Xtez2W7Zu1PLH9bvJgtraN1CDST6LBM/eTOZ9SfwS/lvV8yOfcDpFmwf9bq5cYbXvqsvA==
-  dependencies:
-    "@babel/core" "^7.1.0"
-    "@jest/types" "^24.8.0"
-    babel-plugin-istanbul "^5.1.0"
-    chalk "^2.0.1"
-    convert-source-map "^1.4.0"
-    fast-json-stable-stringify "^2.0.0"
-    graceful-fs "^4.1.15"
-    jest-haste-map "^24.8.0"
-    jest-regex-util "^24.3.0"
-    jest-util "^24.8.0"
-    micromatch "^3.1.10"
-    realpath-native "^1.1.0"
-    slash "^2.0.0"
-    source-map "^0.6.1"
-    write-file-atomic "2.4.1"
-
 "@jest/transform@^24.9.0":
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.9.0.tgz#4ae2768b296553fadab09e9ec119543c90b16c56"
@@ -1087,15 +1048,6 @@
     source-map "^0.6.1"
     write-file-atomic "2.4.1"
 
-"@jest/types@^24.8.0":
-  version "24.8.0"
-  resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.8.0.tgz#f31e25948c58f0abd8c845ae26fcea1491dea7ad"
-  integrity sha512-g17UxVr2YfBtaMUxn9u/4+siG1ptg9IGYAYwvpwn61nBg779RXnjE/m7CxYcIzEt0AbHZZAHSEZNhkE2WxURVg==
-  dependencies:
-    "@types/istanbul-lib-coverage" "^2.0.0"
-    "@types/istanbul-reports" "^1.1.1"
-    "@types/yargs" "^12.0.9"
-
 "@jest/types@^24.9.0":
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59"
@@ -1178,9 +1130,9 @@
   integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
 
 "@types/node@*":
-  version "10.12.18"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
-  integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
+  version "12.7.8"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.8.tgz#cb1bf6800238898bc2ff6ffa5702c3cadd350708"
+  integrity sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A==
 
 "@types/q@^1.5.1":
   version "1.5.1"
@@ -1204,11 +1156,6 @@
   resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.1.0.tgz#c563aa192f39350a1d18da36c5a8da382bbd8228"
   integrity sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==
 
-"@types/yargs@^12.0.9":
-  version "12.0.9"
-  resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.9.tgz#693e76a52f61a2f1e7fb48c0eef167b95ea4ffd0"
-  integrity sha512-sCZy4SxP9rN2w30Hlmg5dtdRwgYQfYRiLo9usw8X9cxlf+H4FqM1xX7+sNH7NNKVdbXMJWqva7iyy+fxh/V7fA==
-
 "@types/yargs@^13.0.0":
   version "13.0.2"
   resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.2.tgz#a64674fc0149574ecd90ba746e932b5a5f7b3653"
@@ -1405,10 +1352,10 @@ acorn-jsx@^3.0.0:
   dependencies:
     acorn "^3.0.4"
 
-acorn-jsx@^5.0.0:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e"
-  integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==
+acorn-jsx@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f"
+  integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==
 
 acorn-walk@^6.0.1, acorn-walk@^6.1.1:
   version "6.1.1"
@@ -1430,6 +1377,11 @@ acorn@^6.0.1, acorn@^6.0.7, acorn@^6.2.0:
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3"
   integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==
 
+acorn@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a"
+  integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==
+
 airbnb-prop-types@^2.13.2:
   version "2.13.2"
   resolved "https://registry.yarnpkg.com/airbnb-prop-types/-/airbnb-prop-types-2.13.2.tgz#43147a5062dd2a4a5600e748a47b64004cc5f7fc"
@@ -1457,9 +1409,9 @@ ajv-keywords@^1.0.0:
   integrity sha1-MU3QpLM2j609/NxU7eYXG4htrzw=
 
 ajv-keywords@^3.1.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a"
-  integrity sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da"
+  integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==
 
 ajv@^4.7.0:
   version "4.11.8"
@@ -1485,9 +1437,9 @@ alphanum-sort@^1.0.0:
   integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
 
 ansi-colors@^3.0.0:
-  version "3.2.3"
-  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
-  integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
+  version "3.2.4"
+  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
+  integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
 
 ansi-escapes@^1.1.0:
   version "1.4.0"
@@ -1721,9 +1673,9 @@ async-each@^1.0.1:
   integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
 
 async-limiter@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
-  integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
+  integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
 
 async@^1.5.2:
   version "1.5.2"
@@ -1802,19 +1754,6 @@ babel-eslint@^10.0.3:
     eslint-visitor-keys "^1.0.0"
     resolve "^1.12.0"
 
-babel-jest@^24.8.0:
-  version "24.8.0"
-  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.8.0.tgz#5c15ff2b28e20b0f45df43fe6b7f2aae93dba589"
-  integrity sha512-+5/kaZt4I9efoXzPlZASyK/lN9qdRKmmUav9smVc0ruPQD7IsfucQ87gpOE8mn2jbDuS6M/YOW6n3v9ZoIfgnw==
-  dependencies:
-    "@jest/transform" "^24.8.0"
-    "@jest/types" "^24.8.0"
-    "@types/babel__core" "^7.1.0"
-    babel-plugin-istanbul "^5.1.0"
-    babel-preset-jest "^24.6.0"
-    chalk "^2.4.2"
-    slash "^2.0.0"
-
 babel-jest@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54"
@@ -1872,13 +1811,6 @@ babel-plugin-istanbul@^5.1.0:
     istanbul-lib-instrument "^3.0.0"
     test-exclude "^5.0.0"
 
-babel-plugin-jest-hoist@^24.6.0:
-  version "24.6.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.6.0.tgz#f7f7f7ad150ee96d7a5e8e2c5da8319579e78019"
-  integrity sha512-3pKNH6hMt9SbOv0F3WVmy5CWQ4uogS3k0GY5XLyQHJ9EGpAT9XWkFd2ZiXXtkwFHdAHa5j7w7kfxSP5lAIwu7w==
-  dependencies:
-    "@types/babel__traverse" "^7.0.6"
-
 babel-plugin-jest-hoist@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756"
@@ -1940,14 +1872,6 @@ babel-plugin-transform-react-remove-prop-types@^0.4.24:
   resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a"
   integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==
 
-babel-preset-jest@^24.6.0:
-  version "24.6.0"
-  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz#66f06136eefce87797539c0d63f1769cc3915984"
-  integrity sha512-pdZqLEdmy1ZK5kyRUfvBb2IfTPb2BUvIJczlPspS8fWmBQslNNDBqVfh7BW5leOVJMDZKzjD8XEyABTk6gQ5yw==
-  dependencies:
-    "@babel/plugin-syntax-object-rest-spread" "^7.0.0"
-    babel-plugin-jest-hoist "^24.6.0"
-
 babel-preset-jest@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc"
@@ -2027,9 +1951,9 @@ big.js@^5.2.2:
   integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
 
 binary-extensions@^1.0.0:
-  version "1.12.0"
-  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14"
-  integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==
+  version "1.13.1"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
+  integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
 
 binary-extensions@^2.0.0:
   version "2.0.0"
@@ -2474,7 +2398,7 @@ cheerio@^1.0.0-rc.2:
   optionalDependencies:
     fsevents "^2.0.6"
 
-chokidar@^2.0.2, chokidar@^2.1.6:
+chokidar@^2.0.2:
   version "2.1.6"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5"
   integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==
@@ -2493,10 +2417,29 @@ chokidar@^2.0.2, chokidar@^2.1.6:
   optionalDependencies:
     fsevents "^1.2.7"
 
+chokidar@^2.1.8:
+  version "2.1.8"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
+  integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
+  dependencies:
+    anymatch "^2.0.0"
+    async-each "^1.0.1"
+    braces "^2.3.2"
+    glob-parent "^3.1.0"
+    inherits "^2.0.3"
+    is-binary-path "^1.0.0"
+    is-glob "^4.0.0"
+    normalize-path "^3.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.2.1"
+    upath "^1.1.1"
+  optionalDependencies:
+    fsevents "^1.2.7"
+
 chownr@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
-  integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142"
+  integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==
 
 chrome-trace-event@^1.0.0:
   version "1.0.0"
@@ -2668,9 +2611,9 @@ commondir@^1.0.1:
   integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
 
 component-emitter@^1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
-  integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+  integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
 
 compressible@~2.0.16:
   version "2.0.17"
@@ -3219,7 +3162,7 @@ date-now@^0.1.4:
   resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
   integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=
 
-debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
+debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
   version "2.6.9"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
   integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -3233,7 +3176,7 @@ debug@=3.1.0:
   dependencies:
     ms "2.0.0"
 
-debug@^3.2.5:
+debug@^3.0.0, debug@^3.2.5, debug@^3.2.6:
   version "3.2.6"
   resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
   integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
@@ -3258,9 +3201,16 @@ decode-uri-component@^0.2.0:
   integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
 
 deep-equal@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
-  integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.0.tgz#3103cdf8ab6d32cf4a8df7865458f2b8d33f3745"
+  integrity sha512-ZbfWJq/wN1Z273o7mUSjILYqehAktR2NVoSrOukDkU9kg2v/Uv89yU4Cvz8seJeAmtN5oqiefKq8FPuXOboqLw==
+  dependencies:
+    is-arguments "^1.0.4"
+    is-date-object "^1.0.1"
+    is-regex "^1.0.4"
+    object-is "^1.0.1"
+    object-keys "^1.1.1"
+    regexp.prototype.flags "^1.2.0"
 
 deep-extend@^0.5.1:
   version "0.5.1"
@@ -3610,13 +3560,20 @@ encoding@^0.1.11:
   dependencies:
     iconv-lite "~0.4.13"
 
-end-of-stream@^1.0.0, end-of-stream@^1.1.0:
+end-of-stream@^1.0.0:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
   integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
   dependencies:
     once "^1.4.0"
 
+end-of-stream@^1.1.0:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+  integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+  dependencies:
+    once "^1.4.0"
+
 enhanced-resolve@4.1.0, enhanced-resolve@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f"
@@ -3913,14 +3870,14 @@ eslint-scope@^5.0.0:
     esrecurse "^4.1.0"
     estraverse "^4.1.1"
 
-eslint-utils@^1.3.1:
+eslint-utils@^1.4.2:
   version "1.4.2"
   resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab"
   integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==
   dependencies:
     eslint-visitor-keys "^1.0.0"
 
-eslint-visitor-keys@^1.0.0:
+eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
   integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
@@ -3964,10 +3921,10 @@ eslint@^2.7.0:
     text-table "~0.2.0"
     user-home "^2.0.0"
 
-eslint@^6.1.0:
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.1.0.tgz#06438a4a278b1d84fb107d24eaaa35471986e646"
-  integrity sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==
+eslint@^6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.4.0.tgz#5aa9227c3fbe921982b2eda94ba0d7fae858611a"
+  integrity sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==
   dependencies:
     "@babel/code-frame" "^7.0.0"
     ajv "^6.10.0"
@@ -3976,9 +3933,9 @@ eslint@^6.1.0:
     debug "^4.0.1"
     doctrine "^3.0.0"
     eslint-scope "^5.0.0"
-    eslint-utils "^1.3.1"
-    eslint-visitor-keys "^1.0.0"
-    espree "^6.0.0"
+    eslint-utils "^1.4.2"
+    eslint-visitor-keys "^1.1.0"
+    espree "^6.1.1"
     esquery "^1.0.1"
     esutils "^2.0.2"
     file-entry-cache "^5.0.1"
@@ -4015,14 +3972,14 @@ espree@^3.1.6:
     acorn "^5.5.0"
     acorn-jsx "^3.0.0"
 
-espree@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/espree/-/espree-6.0.0.tgz#716fc1f5a245ef5b9a7fdb1d7b0d3f02322e75f6"
-  integrity sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==
+espree@^6.1.1:
+  version "6.1.1"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de"
+  integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==
   dependencies:
-    acorn "^6.0.7"
-    acorn-jsx "^5.0.0"
-    eslint-visitor-keys "^1.0.0"
+    acorn "^7.0.0"
+    acorn-jsx "^5.0.2"
+    eslint-visitor-keys "^1.1.0"
 
 esprima@^3.1.3:
   version "3.1.3"
@@ -4071,10 +4028,10 @@ event-emitter@~0.3.5:
     d "1"
     es5-ext "~0.10.14"
 
-eventemitter3@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163"
-  integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==
+eventemitter3@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
+  integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
 
 events@^1.0.0:
   version "1.1.1"
@@ -4277,9 +4234,9 @@ faye-websocket@^0.10.0:
     websocket-driver ">=0.5.1"
 
 faye-websocket@~0.11.1:
-  version "0.11.1"
-  resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38"
-  integrity sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=
+  version "0.11.3"
+  resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e"
+  integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==
   dependencies:
     websocket-driver ">=0.5.1"
 
@@ -4481,11 +4438,11 @@ follow-redirects@1.5.10:
     debug "=3.1.0"
 
 follow-redirects@^1.0.0:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.6.0.tgz#d12452c031e8c67eb6637d861bfc7a8090167933"
-  integrity sha512-4Oh4eI3S9OueVV41AgJ1oLjpaJUhbJ7JDGOMhe0AFqoSejl5Q2nn3eGglAzRUKVKZE8jG5MNn66TjCJMAnpsWA==
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f"
+  integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==
   dependencies:
-    debug "=3.1.0"
+    debug "^3.0.0"
 
 font-awesome@^4.7.0:
   version "4.7.0"
@@ -4574,11 +4531,11 @@ fs-extra@^8.0.1:
     universalify "^0.1.0"
 
 fs-minipass@^1.2.5:
-  version "1.2.5"
-  resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
-  integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
+  integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
   dependencies:
-    minipass "^2.2.1"
+    minipass "^2.6.0"
 
 fs-write-stream-atomic@^1.0.8:
   version "1.0.10"
@@ -4801,7 +4758,12 @@ gonzales-pe-sl@^4.2.3:
   dependencies:
     minimist "1.1.x"
 
-graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+graceful-fs@^4.1.11:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02"
+  integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==
+
+graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
   version "4.1.15"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
   integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
@@ -5082,10 +5044,10 @@ http-link-header@^1.0.2:
   resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-1.0.2.tgz#bea50f02e1c7996021f1013b428c63f77e0f4e11"
   integrity sha512-z6YOZ8ZEnejkcCWlGZzYXNa6i+ZaTfiTg3WhlV/YvnNya3W/RbX1bMVUMTuCrg/DrtTCQxaFCkXCz4FtLpcebg==
 
-http-parser-js@>=0.4.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8"
-  integrity sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==
+"http-parser-js@>=0.4.0 <0.4.11":
+  version "0.4.10"
+  resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4"
+  integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=
 
 http-proxy-middleware@^0.19.1:
   version "0.19.1"
@@ -5098,11 +5060,11 @@ http-proxy-middleware@^0.19.1:
     micromatch "^3.1.10"
 
 http-proxy@^1.17.0:
-  version "1.17.0"
-  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a"
-  integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==
+  version "1.18.0"
+  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
+  integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
   dependencies:
-    eventemitter3 "^3.0.0"
+    eventemitter3 "^4.0.0"
     follow-redirects "^1.0.0"
     requires-port "^1.0.0"
 
@@ -5150,9 +5112,9 @@ iferr@^0.1.5:
   integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
 
 ignore-walk@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
-  integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.2.tgz#99d83a246c196ea5c93ef9315ad7b0819c35069b"
+  integrity sha512-EXyErtpHbn75ZTsOADsfx6J/FPo6/5cjev46PXrcTpd8z3BoRkXgYu9/JVqrI7tusjmwCZutGeRJeU0Wo1e4Cw==
   dependencies:
     minimatch "^3.0.4"
 
@@ -5245,16 +5207,21 @@ inflight@^1.0.4:
     once "^1.3.0"
     wrappy "1"
 
-inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
-  integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
 
 inherits@2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
   integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
 
+inherits@2.0.3, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+  integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+
 ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
   version "1.3.5"
   resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
@@ -5377,20 +5344,25 @@ ip@^1.1.0, ip@^1.1.5:
   resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
   integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
 
-ipaddr.js@1.9.0, ipaddr.js@^1.9.0:
+ipaddr.js@1.9.0:
   version "1.9.0"
   resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
   integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
 
+ipaddr.js@^1.9.0:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+  integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
 is-absolute-url@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
   integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=
 
-is-absolute-url@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.0.tgz#eb21d69df2ed8ef72a3e6f243e216563036a0913"
-  integrity sha512-3OkP8XrM2Xq4/IxsJnClfMp3OaM3TAatLPLKPeWcxLBTrpe6hihwtX+XZfJTcXg/FTRi4qjy0y/C5qiyNxY24g==
+is-absolute-url@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698"
+  integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==
 
 is-accessor-descriptor@^0.1.6:
   version "0.1.6"
@@ -5406,6 +5378,11 @@ is-accessor-descriptor@^1.0.0:
   dependencies:
     kind-of "^6.0.0"
 
+is-arguments@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3"
+  integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==
+
 is-arrayish@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -5612,9 +5589,9 @@ is-obj@^1.0.0:
   integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
 
 is-path-cwd@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.1.0.tgz#2e0c7e463ff5b7a0eb60852d851a6809347a124c"
-  integrity sha512-Sc5j3/YnM8tDeyCsVeKlm/0p95075DyLmDEIkSgQ7mXkrOX+uTCtmQFm0CYzVyJwcCCmO3k8qfJt17SxQwB5Zw==
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
+  integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
 
 is-path-in-cwd@^2.0.0:
   version "2.1.0"
@@ -5635,7 +5612,7 @@ is-plain-obj@^1.0.0:
   resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
   integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
 
-is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
   integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
@@ -5910,25 +5887,6 @@ jest-get-type@^24.9.0:
   resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e"
   integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==
 
-jest-haste-map@^24.8.0:
-  version "24.8.0"
-  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.8.0.tgz#51794182d877b3ddfd6e6d23920e3fe72f305800"
-  integrity sha512-ZBPRGHdPt1rHajWelXdqygIDpJx8u3xOoLyUBWRW28r3tagrgoepPrzAozW7kW9HrQfhvmiv1tncsxqHJO1onQ==
-  dependencies:
-    "@jest/types" "^24.8.0"
-    anymatch "^2.0.0"
-    fb-watchman "^2.0.0"
-    graceful-fs "^4.1.15"
-    invariant "^2.2.4"
-    jest-serializer "^24.4.0"
-    jest-util "^24.8.0"
-    jest-worker "^24.6.0"
-    micromatch "^3.1.10"
-    sane "^4.0.3"
-    walker "^1.0.7"
-  optionalDependencies:
-    fsevents "^1.2.7"
-
 jest-haste-map@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d"
@@ -5988,20 +5946,6 @@ jest-matcher-utils@^24.9.0:
     jest-get-type "^24.9.0"
     pretty-format "^24.9.0"
 
-jest-message-util@^24.8.0:
-  version "24.8.0"
-  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.8.0.tgz#0d6891e72a4beacc0292b638685df42e28d6218b"
-  integrity sha512-p2k71rf/b6ns8btdB0uVdljWo9h0ovpnEe05ZKWceQGfXYr4KkzgKo3PBi8wdnd9OtNh46VpNIJynUn/3MKm1g==
-  dependencies:
-    "@babel/code-frame" "^7.0.0"
-    "@jest/test-result" "^24.8.0"
-    "@jest/types" "^24.8.0"
-    "@types/stack-utils" "^1.0.1"
-    chalk "^2.0.1"
-    micromatch "^3.1.10"
-    slash "^2.0.0"
-    stack-utils "^1.0.1"
-
 jest-message-util@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3"
@@ -6016,13 +5960,6 @@ jest-message-util@^24.9.0:
     slash "^2.0.0"
     stack-utils "^1.0.1"
 
-jest-mock@^24.8.0:
-  version "24.8.0"
-  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.8.0.tgz#2f9d14d37699e863f1febf4e4d5a33b7fdbbde56"
-  integrity sha512-6kWugwjGjJw+ZkK4mDa0Df3sDlUTsV47MSrT0nGQ0RBWJbpODDQ8MHDVtGtUYBne3IwZUhtB7elxHspU79WH3A==
-  dependencies:
-    "@jest/types" "^24.8.0"
-
 jest-mock@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6"
@@ -6119,11 +6056,6 @@ jest-runtime@^24.9.0:
     strip-bom "^3.0.0"
     yargs "^13.3.0"
 
-jest-serializer@^24.4.0:
-  version "24.4.0"
-  resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.4.0.tgz#f70c5918c8ea9235ccb1276d232e459080588db3"
-  integrity sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q==
-
 jest-serializer@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73"
@@ -6148,24 +6080,6 @@ jest-snapshot@^24.9.0:
     pretty-format "^24.9.0"
     semver "^6.2.0"
 
-jest-util@^24.8.0:
-  version "24.8.0"
-  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.8.0.tgz#41f0e945da11df44cc76d64ffb915d0716f46cd1"
-  integrity sha512-DYZeE+XyAnbNt0BG1OQqKy/4GVLPtzwGx5tsnDrFcax36rVE3lTA5fbvgmbVPUZf9w77AJ8otqR4VBbfFJkUZA==
-  dependencies:
-    "@jest/console" "^24.7.1"
-    "@jest/fake-timers" "^24.8.0"
-    "@jest/source-map" "^24.3.0"
-    "@jest/test-result" "^24.8.0"
-    "@jest/types" "^24.8.0"
-    callsites "^3.0.0"
-    chalk "^2.0.1"
-    graceful-fs "^4.1.15"
-    is-ci "^2.0.0"
-    mkdirp "^0.5.1"
-    slash "^2.0.0"
-    source-map "^0.6.0"
-
 jest-util@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162"
@@ -6341,9 +6255,9 @@ json-stringify-safe@~5.0.1:
   integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
 
 json3@^3.3.2:
-  version "3.3.2"
-  resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
-  integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=
+  version "3.3.3"
+  resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81"
+  integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==
 
 json5@^0.5.0:
   version "0.5.1"
@@ -6622,10 +6536,10 @@ lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11,
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
   integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
 
-loglevel@^1.6.3:
-  version "1.6.3"
-  resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280"
-  integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==
+loglevel@^1.6.4:
+  version "1.6.4"
+  resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.4.tgz#f408f4f006db8354d0577dcf6d33485b3cb90d56"
+  integrity sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==
 
 loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
   version "1.4.0"
@@ -6724,13 +6638,13 @@ media-typer@0.3.0:
   integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
 
 mem@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf"
-  integrity sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
+  integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==
   dependencies:
     map-age-cleaner "^0.1.1"
-    mimic-fn "^1.0.0"
-    p-is-promise "^1.1.0"
+    mimic-fn "^2.0.0"
+    p-is-promise "^2.0.0"
 
 memoize-one@^5.0.0:
   version "5.0.4"
@@ -6799,24 +6713,29 @@ miller-rabin@^4.0.0:
     bn.js "^4.0.0"
     brorand "^1.0.1"
 
-mime-db@1.40.0, "mime-db@>= 1.40.0 < 2":
+mime-db@1.40.0:
   version "1.40.0"
   resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
   integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
 
+"mime-db@>= 1.40.0 < 2":
+  version "1.42.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac"
+  integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==
+
 mime-db@~1.37.0:
   version "1.37.0"
   resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8"
   integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==
 
-mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19:
+mime-types@^2.1.12, mime-types@~2.1.19:
   version "2.1.21"
   resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96"
   integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==
   dependencies:
     mime-db "~1.37.0"
 
-mime-types@~2.1.24:
+mime-types@~2.1.17, mime-types@~2.1.24:
   version "2.1.24"
   resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
   integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
@@ -6828,20 +6747,25 @@ mime@1.6.0:
   resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
   integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
 
-mime@^2.4.2:
-  version "2.4.3"
-  resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe"
-  integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==
+mime@^2.4.4:
+  version "2.4.4"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
+  integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
 
 mimic-fn@^1.0.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
   integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
 
-mini-css-extract-plugin@^0.7.0:
-  version "0.7.0"
-  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.7.0.tgz#5ba8290fbb4179a43dd27cca444ba150bee743a0"
-  integrity sha512-RQIw6+7utTYn8DBGsf/LpRgZCJMpZt+kuawJ/fju0KiOL6nAaTBNmCJwS7HtwSCXfS47gCkmtBFS7HdsquhdxQ==
+mimic-fn@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+mini-css-extract-plugin@^0.8.0:
+  version "0.8.0"
+  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz#81d41ec4fe58c713a96ad7c723cdb2d0bd4d70e1"
+  integrity sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw==
   dependencies:
     loader-utils "^1.1.0"
     normalize-url "1.9.1"
@@ -6885,20 +6809,28 @@ minimist@~0.0.1:
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
   integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
 
-minipass@^2.2.1, minipass@^2.3.4:
-  version "2.3.5"
-  resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
-  integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
+minipass@^2.6.0, minipass@^2.8.6:
+  version "2.8.6"
+  resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.8.6.tgz#620d889ace26356391d010ecb9458749df9b6db5"
+  integrity sha512-lFG7d6g3+/UaFDCOtqPiKAC9zngWWsQZl1g5q6gaONqrjq61SX2xFqXMleQiFVyDpYwa018E9hmlAFY22PCb+A==
   dependencies:
     safe-buffer "^5.1.2"
     yallist "^3.0.0"
 
-minizlib@^1.1.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
-  integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
+minipass@^2.9.0:
+  version "2.9.0"
+  resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
+  integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
+  dependencies:
+    safe-buffer "^5.1.2"
+    yallist "^3.0.0"
+
+minizlib@^1.2.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.2.tgz#5d24764998f98112586f7e566bd4c0999769dad4"
+  integrity sha512-lsNFqSHdJ21EwKzCp12HHJGxSMtHkCW1EMA9cceG3MkMNARjuWotZnMe3NKNshAvFXpm4loZqmYsCmRwhS2JMw==
   dependencies:
-    minipass "^2.2.1"
+    minipass "^2.9.0"
 
 mississippi@^3.0.0:
   version "3.0.0"
@@ -6966,11 +6898,16 @@ ms@2.0.0:
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
   integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
 
-ms@2.1.1, ms@^2.1.1:
+ms@2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
   integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
 
+ms@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
 multicast-dns-service-types@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
@@ -7033,11 +6970,11 @@ nearley@^2.7.10:
     semver "^5.4.1"
 
 needle@^2.2.1:
-  version "2.2.4"
-  resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e"
-  integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
+  integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
   dependencies:
-    debug "^2.1.2"
+    debug "^3.2.6"
     iconv-lite "^0.4.4"
     sax "^1.2.4"
 
@@ -7074,10 +7011,10 @@ node-fetch@^2.3.0:
   resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
   integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
 
-node-forge@0.7.5:
-  version "0.7.5"
-  resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df"
-  integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==
+node-forge@0.8.2:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.2.tgz#b4bcc59fb12ce77a8825fc6a783dfe3182499c5a"
+  integrity sha512-mXQ9GBq1N3uDCyV1pdSzgIguwgtVpM7f5/5J4ipz12PKWElmPpVWLDuWl8iXmhysr21+WmX/OJ5UKx82wjomgg==
 
 node-int64@^0.4.0:
   version "0.4.0"
@@ -7210,14 +7147,14 @@ normalize-url@^3.0.0:
   integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
 
 npm-bundled@^1.0.1:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979"
-  integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
+  integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
 
 npm-packlist@^1.1.6:
-  version "1.1.12"
-  resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.12.tgz#22bde2ebc12e72ca482abd67afc51eb49377243a"
-  integrity sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g==
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44"
+  integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==
   dependencies:
     ignore-walk "^3.0.1"
     npm-bundled "^1.0.1"
@@ -7305,6 +7242,11 @@ object-keys@^1.0.11, object-keys@^1.0.12:
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2"
   integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==
 
+object-keys@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+  integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
 object-visit@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
@@ -7507,10 +7449,10 @@ p-finally@^1.0.0:
   resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
   integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
 
-p-is-promise@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e"
-  integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=
+p-is-promise@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
+  integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
 
 p-limit@^1.1.0:
   version "1.3.0"
@@ -7520,9 +7462,9 @@ p-limit@^1.1.0:
     p-try "^1.0.0"
 
 p-limit@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.1.0.tgz#1d5a0d20fb12707c758a655f6bbc4386b5930d68"
-  integrity sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537"
+  integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==
   dependencies:
     p-try "^2.0.0"
 
@@ -7577,9 +7519,9 @@ p-try@^1.0.0:
   integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
 
 p-try@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
-  integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
 
 packet-reader@0.3.1:
   version "0.3.1"
@@ -7887,10 +7829,10 @@ pn@^1.1.0:
   resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
   integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==
 
-portfinder@^1.0.21:
-  version "1.0.21"
-  resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.21.tgz#60e1397b95ac170749db70034ece306b9a27e324"
-  integrity sha512-ESabpDCzmBS3ekHbmpAIiESq3udRsCBGiBZLsC+HgBKv2ezb0R4oG+7RnYEVZ/ZCfhel5Tx3UzdNWA0Lox2QCA==
+portfinder@^1.0.24:
+  version "1.0.24"
+  resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.24.tgz#11efbc6865f12f37624b6531ead1d809ed965cfa"
+  integrity sha512-ekRl7zD2qxYndYflwiryJwMioBI7LI7rVXg3EnLK3sjkouT5eOuhS3gS255XxBksa30VG8UPZYZCdgfGOfkSUg==
   dependencies:
     async "^1.5.2"
     debug "^2.2.0"
@@ -8318,9 +8260,9 @@ private@^0.1.6:
   integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
 
 process-nextick-args@~2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
-  integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+  integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
 
 process@^0.11.10:
   version "0.11.10"
@@ -8486,10 +8428,10 @@ querystring@0.2.0:
   resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
   integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
 
-querystringify@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef"
-  integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==
+querystringify@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
+  integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
 
 quote@^0.4.0:
   version "0.4.0"
@@ -8883,9 +8825,9 @@ read-pkg@^3.0.0:
     util-deprecate "~1.0.1"
 
 readable-stream@^3.0.6:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06"
-  integrity sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc"
+  integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==
   dependencies:
     inherits "^2.0.3"
     string_decoder "^1.1.1"
@@ -9012,6 +8954,13 @@ regexp-tree@^0.1.13:
   resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.13.tgz#5b19ab9377edc68bc3679256840bb29afc158d7f"
   integrity sha512-hwdV/GQY5F8ReLZWO+W1SRoN5YfpOKY6852+tBFcma72DKBIcHjPRIlIvQN35bCOljuAfP2G2iB0FC/w236mUw==
 
+regexp.prototype.flags@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c"
+  integrity sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==
+  dependencies:
+    define-properties "^1.1.2"
+
 regexpp@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
@@ -9244,13 +9193,20 @@ rgba-regex@^1.0.0:
   resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
   integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
 
-rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.2:
+rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@~2.6.2:
   version "2.6.3"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
   integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
   dependencies:
     glob "^7.1.3"
 
+rimraf@^2.6.1, rimraf@^2.6.3:
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+  integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
+  dependencies:
+    glob "^7.1.3"
+
 rimraf@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b"
@@ -9312,11 +9268,16 @@ rxjs@^6.4.0:
   dependencies:
     tslib "^1.9.0"
 
-safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+safe-buffer@5.1.2, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
   integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
 
+safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
+  integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+
 safe-regex@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
@@ -9376,10 +9337,10 @@ sass-loader@^7.0.3:
     pify "^3.0.0"
     semver "^5.5.0"
 
-sass@^1.22.9:
-  version "1.22.9"
-  resolved "https://registry.yarnpkg.com/sass/-/sass-1.22.9.tgz#41a2ed6038027f58be2bd5041293452a29c2cb84"
-  integrity sha512-FzU1X2V8DlnqabrL4u7OBwD2vcOzNMongEJEx3xMEhWY/v26FFR3aG0hyeu2T965sfR0E9ufJwmG+Qjz78vFPQ==
+sass@^1.22.12:
+  version "1.22.12"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.22.12.tgz#5cbdd38720ffd1857da695331faee9f634bcb5d7"
+  integrity sha512-u5Rxn+dKTPCW5/11kMNxtmqKsxCjcpnqj9CaJoru1NqeJ0DOa9rOM00e0HqmseTAatGkKoLY+jaNecMYevu1gg==
   dependencies:
     chokidar ">=2.0.0 <4.0.0"
 
@@ -9426,14 +9387,14 @@ select-hose@^2.0.0:
   resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
   integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
 
-selfsigned@^1.10.4:
-  version "1.10.4"
-  resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd"
-  integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==
+selfsigned@^1.10.6:
+  version "1.10.6"
+  resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.6.tgz#7b3cd37ed9c2034261a173af1a1aae27d8169b67"
+  integrity sha512-i3+CeqxL7DpAazgVpAGdKMwHuL63B5nhJMh9NQ7xmChGkA3jNFflq6Jyo1LLJYcr3idWiNOPWHCrm4zMayLG4w==
   dependencies:
-    node-forge "0.7.5"
+    node-forge "0.8.2"
 
-"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0:
+"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0:
   version "5.7.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
   integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
@@ -9443,6 +9404,11 @@ semver@4.3.2:
   resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7"
   integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=
 
+semver@^5.3.0, semver@^5.5.0:
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
 semver@^6.0.0, semver@^6.1.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
   version "6.3.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
@@ -9500,20 +9466,10 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
   resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
   integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
 
-set-value@^0.4.3:
-  version "0.4.3"
-  resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
-  integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE=
-  dependencies:
-    extend-shallow "^2.0.1"
-    is-extendable "^0.1.1"
-    is-plain-object "^2.0.1"
-    to-object-path "^0.3.0"
-
-set-value@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
-  integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==
+set-value@^2.0.0, set-value@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+  integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
   dependencies:
     extend-shallow "^2.0.1"
     is-extendable "^0.1.1"
@@ -9645,10 +9601,10 @@ snapdragon@^0.8.1:
     source-map-resolve "^0.5.0"
     use "^3.1.0"
 
-sockjs-client@1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177"
-  integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==
+sockjs-client@1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5"
+  integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==
   dependencies:
     debug "^3.2.5"
     eventsource "^1.0.7"
@@ -9922,13 +9878,20 @@ string.prototype.trim@^1.1.2:
     es-abstract "^1.5.0"
     function-bind "^1.0.2"
 
-string_decoder@^1.0.0, string_decoder@^1.1.1:
+string_decoder@^1.0.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
   integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
   dependencies:
     safe-buffer "~5.1.0"
 
+string_decoder@^1.1.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+  integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+  dependencies:
+    safe-buffer "~5.2.0"
+
 string_decoder@~1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@@ -10097,17 +10060,17 @@ tapable@^1.0.0, tapable@^1.1.0:
   integrity sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==
 
 tar@^4:
-  version "4.4.8"
-  resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
-  integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
+  version "4.4.13"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
+  integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==
   dependencies:
     chownr "^1.1.1"
     fs-minipass "^1.2.5"
-    minipass "^2.3.4"
-    minizlib "^1.1.1"
+    minipass "^2.8.6"
+    minizlib "^1.2.1"
     mkdirp "^0.5.0"
     safe-buffer "^5.1.2"
-    yallist "^3.0.2"
+    yallist "^3.0.3"
 
 tcomb@^2.5.0:
   version "2.7.0"
@@ -10429,14 +10392,14 @@ unicode-property-aliases-ecmascript@^1.0.4:
   integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
 
 union-value@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
-  integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+  integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
   dependencies:
     arr-union "^3.1.0"
     get-value "^2.0.6"
     is-extendable "^0.1.1"
-    set-value "^0.4.3"
+    set-value "^2.0.1"
 
 uniq@^1.0.1:
   version "1.0.1"
@@ -10486,9 +10449,9 @@ unset-value@^1.0.0:
     isobject "^3.0.0"
 
 upath@^1.1.1:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068"
-  integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
+  integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
 
 uri-js@^4.2.2:
   version "4.2.2"
@@ -10503,11 +10466,11 @@ urix@^0.1.0:
   integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
 
 url-parse@^1.4.3:
-  version "1.4.4"
-  resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8"
-  integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==
+  version "1.4.7"
+  resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
+  integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
   dependencies:
-    querystringify "^2.0.0"
+    querystringify "^2.1.1"
     requires-port "^1.0.0"
 
 url@^0.11.0:
@@ -10562,7 +10525,12 @@ utils-merge@1.0.1:
   resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
   integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
 
-uuid@^3.0.1, uuid@^3.1.0, uuid@^3.3.2:
+uuid@^3.0.1, uuid@^3.3.2:
+  version "3.3.3"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
+  integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
+
+uuid@^3.1.0:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
   integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
@@ -10719,24 +10687,25 @@ webpack-cli@^3.3.7:
     v8-compile-cache "2.0.3"
     yargs "13.2.4"
 
-webpack-dev-middleware@^3.7.0:
-  version "3.7.0"
-  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz#ef751d25f4e9a5c8a35da600c5fda3582b5c6cff"
-  integrity sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA==
+webpack-dev-middleware@^3.7.1:
+  version "3.7.2"
+  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3"
+  integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==
   dependencies:
     memory-fs "^0.4.1"
-    mime "^2.4.2"
+    mime "^2.4.4"
+    mkdirp "^0.5.1"
     range-parser "^1.2.1"
     webpack-log "^2.0.0"
 
 webpack-dev-server@^3.8.0:
-  version "3.8.0"
-  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.8.0.tgz#06cc4fc2f440428508d0e9770da1fef10e5ef28d"
-  integrity sha512-Hs8K9yI6pyMvGkaPTeTonhD6JXVsigXDApYk9JLW4M7viVBspQvb1WdAcWxqtmttxNW4zf2UFLsLNe0y87pIGQ==
+  version "3.8.1"
+  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.8.1.tgz#485b64c4aadc23f601e72114b40c1b1fea31d9f1"
+  integrity sha512-9F5DnfFA9bsrhpUCAfQic/AXBVHvq+3gQS+x6Zj0yc1fVVE0erKh2MV4IV12TBewuTrYeeTIRwCH9qLMvdNvTw==
   dependencies:
     ansi-html "0.0.7"
     bonjour "^3.5.0"
-    chokidar "^2.1.6"
+    chokidar "^2.1.8"
     compression "^1.7.4"
     connect-history-api-fallback "^1.6.0"
     debug "^4.1.1"
@@ -10747,23 +10716,23 @@ webpack-dev-server@^3.8.0:
     import-local "^2.0.0"
     internal-ip "^4.3.0"
     ip "^1.1.5"
-    is-absolute-url "^3.0.0"
+    is-absolute-url "^3.0.2"
     killable "^1.0.1"
-    loglevel "^1.6.3"
+    loglevel "^1.6.4"
     opn "^5.5.0"
     p-retry "^3.0.1"
-    portfinder "^1.0.21"
+    portfinder "^1.0.24"
     schema-utils "^1.0.0"
-    selfsigned "^1.10.4"
+    selfsigned "^1.10.6"
     semver "^6.3.0"
     serve-index "^1.9.1"
     sockjs "0.3.19"
-    sockjs-client "1.3.0"
+    sockjs-client "1.4.0"
     spdy "^4.0.1"
     strip-ansi "^3.0.1"
     supports-color "^6.1.0"
     url "^0.11.0"
-    webpack-dev-middleware "^3.7.0"
+    webpack-dev-middleware "^3.7.1"
     webpack-log "^2.0.0"
     ws "^6.2.1"
     yargs "12.0.5"
@@ -10821,11 +10790,12 @@ webpack@^4.35.3:
     webpack-sources "^1.3.0"
 
 websocket-driver@>=0.5.1:
-  version "0.7.0"
-  resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb"
-  integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=
+  version "0.7.3"
+  resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9"
+  integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==
   dependencies:
-    http-parser-js ">=0.4.0"
+    http-parser-js ">=0.4.0 <0.4.11"
+    safe-buffer ">=5.1.0"
     websocket-extensions ">=0.1.1"
 
 websocket-extensions@>=0.1.1:
@@ -10985,10 +10955,10 @@ xtend@^4.0.0, xtend@~4.0.1:
   resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
   integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
 
-yallist@^3.0.0, yallist@^3.0.2:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
-  integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
+yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.0.tgz#906cc2100972dc2625ae78f566a2577230a1d6f7"
+  integrity sha512-6gpP93MR+VOOehKbCPchro3wFZNSNmek8A2kbkOAZLIZAYx1KP/zAqwO0sOHi3xJEb+UBz8NaYt/17UNit1Q9w==
 
 yargs-parser@^11.1.1:
   version "11.1.1"