about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.env.nanobox254
-rw-r--r--.ruby-gemset1
-rw-r--r--.ruby-version2
-rw-r--r--Dockerfile4
-rw-r--r--Gemfile12
-rw-r--r--Gemfile.lock104
-rw-r--r--app/controllers/api/v1/filters/statuses_controller.rb44
-rw-r--r--app/controllers/auth/registrations_controller.rb6
-rw-r--r--app/controllers/filters/statuses_controller.rb49
-rw-r--r--app/controllers/filters_controller.rb2
-rw-r--r--app/javascript/flavours/glitch/actions/filters.js69
-rw-r--r--app/javascript/flavours/glitch/actions/importer/index.js11
-rw-r--r--app/javascript/flavours/glitch/actions/importer/normalizer.js12
-rw-r--r--app/javascript/flavours/glitch/actions/notifications.js32
-rw-r--r--app/javascript/flavours/glitch/actions/statuses.js4
-rw-r--r--app/javascript/flavours/glitch/actions/streaming.js4
-rw-r--r--app/javascript/flavours/glitch/actions/tags.js6
-rw-r--r--app/javascript/flavours/glitch/actions/timelines.js16
-rw-r--r--app/javascript/flavours/glitch/components/icon_button.js14
-rw-r--r--app/javascript/flavours/glitch/components/status.js29
-rw-r--r--app/javascript/flavours/glitch/components/status_action_bar.js23
-rw-r--r--app/javascript/flavours/glitch/containers/status_container.js51
-rw-r--r--app/javascript/flavours/glitch/features/audio/index.js64
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/language_dropdown.js19
-rw-r--r--app/javascript/flavours/glitch/features/filters/added_to_filter.js102
-rw-r--r--app/javascript/flavours/glitch/features/filters/select_filter.js192
-rw-r--r--app/javascript/flavours/glitch/features/local_settings/page/index.js23
-rw-r--r--app/javascript/flavours/glitch/features/status/components/detailed_status.js4
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/filter_modal.js134
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/modal_root.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/index.js3
-rw-r--r--app/javascript/flavours/glitch/reducers/filters.js41
-rw-r--r--app/javascript/flavours/glitch/reducers/local_settings.js1
-rw-r--r--app/javascript/flavours/glitch/reducers/notifications.js12
-rw-r--r--app/javascript/flavours/glitch/selectors/index.js118
-rw-r--r--app/javascript/flavours/glitch/styles/components/media.scss7
-rw-r--r--app/javascript/flavours/glitch/styles/components/modal.scss18
-rw-r--r--app/javascript/flavours/glitch/util/async-components.js4
-rw-r--r--app/javascript/flavours/glitch/util/filters.js16
-rw-r--r--app/javascript/flavours/glitch/util/icons.js13
-rw-r--r--app/javascript/mastodon/actions/filters.js93
-rw-r--r--app/javascript/mastodon/actions/notifications.js19
-rw-r--r--app/javascript/mastodon/actions/statuses.js4
-rw-r--r--app/javascript/mastodon/actions/tags.js6
-rw-r--r--app/javascript/mastodon/components/icon_button.js14
-rw-r--r--app/javascript/mastodon/components/status.js7
-rw-r--r--app/javascript/mastodon/components/status_action_bar.js16
-rw-r--r--app/javascript/mastodon/containers/status_container.js9
-rw-r--r--app/javascript/mastodon/features/audio/index.js64
-rw-r--r--app/javascript/mastodon/features/compose/components/language_dropdown.js19
-rw-r--r--app/javascript/mastodon/features/filters/added_to_filter.js102
-rw-r--r--app/javascript/mastodon/features/filters/select_filter.js192
-rw-r--r--app/javascript/mastodon/features/status/components/detailed_status.js4
-rw-r--r--app/javascript/mastodon/features/ui/components/filter_modal.js134
-rw-r--r--app/javascript/mastodon/features/ui/components/modal_root.js2
-rw-r--r--app/javascript/mastodon/features/ui/util/async-components.js4
-rw-r--r--app/javascript/mastodon/locales/af.json18
-rw-r--r--app/javascript/mastodon/locales/ar.json18
-rw-r--r--app/javascript/mastodon/locales/ast.json18
-rw-r--r--app/javascript/mastodon/locales/bg.json18
-rw-r--r--app/javascript/mastodon/locales/bn.json18
-rw-r--r--app/javascript/mastodon/locales/br.json38
-rw-r--r--app/javascript/mastodon/locales/ca.json22
-rw-r--r--app/javascript/mastodon/locales/ckb.json18
-rw-r--r--app/javascript/mastodon/locales/co.json18
-rw-r--r--app/javascript/mastodon/locales/cs.json18
-rw-r--r--app/javascript/mastodon/locales/cy.json18
-rw-r--r--app/javascript/mastodon/locales/da.json22
-rw-r--r--app/javascript/mastodon/locales/de.json22
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json107
-rw-r--r--app/javascript/mastodon/locales/el.json22
-rw-r--r--app/javascript/mastodon/locales/en-GB.json18
-rw-r--r--app/javascript/mastodon/locales/en.json18
-rw-r--r--app/javascript/mastodon/locales/eo.json22
-rw-r--r--app/javascript/mastodon/locales/es-AR.json22
-rw-r--r--app/javascript/mastodon/locales/es-MX.json26
-rw-r--r--app/javascript/mastodon/locales/es.json22
-rw-r--r--app/javascript/mastodon/locales/et.json18
-rw-r--r--app/javascript/mastodon/locales/eu.json18
-rw-r--r--app/javascript/mastodon/locales/fa.json18
-rw-r--r--app/javascript/mastodon/locales/fi.json84
-rw-r--r--app/javascript/mastodon/locales/fr.json22
-rw-r--r--app/javascript/mastodon/locales/fy.json18
-rw-r--r--app/javascript/mastodon/locales/ga.json18
-rw-r--r--app/javascript/mastodon/locales/gd.json52
-rw-r--r--app/javascript/mastodon/locales/gl.json24
-rw-r--r--app/javascript/mastodon/locales/he.json24
-rw-r--r--app/javascript/mastodon/locales/hi.json18
-rw-r--r--app/javascript/mastodon/locales/hr.json18
-rw-r--r--app/javascript/mastodon/locales/hu.json22
-rw-r--r--app/javascript/mastodon/locales/hy.json18
-rw-r--r--app/javascript/mastodon/locales/id.json18
-rw-r--r--app/javascript/mastodon/locales/io.json22
-rw-r--r--app/javascript/mastodon/locales/is.json26
-rw-r--r--app/javascript/mastodon/locales/it.json22
-rw-r--r--app/javascript/mastodon/locales/ja.json22
-rw-r--r--app/javascript/mastodon/locales/ka.json18
-rw-r--r--app/javascript/mastodon/locales/kab.json18
-rw-r--r--app/javascript/mastodon/locales/kk.json18
-rw-r--r--app/javascript/mastodon/locales/kn.json18
-rw-r--r--app/javascript/mastodon/locales/ko.json22
-rw-r--r--app/javascript/mastodon/locales/ku.json68
-rw-r--r--app/javascript/mastodon/locales/kw.json18
-rw-r--r--app/javascript/mastodon/locales/lt.json18
-rw-r--r--app/javascript/mastodon/locales/lv.json22
-rw-r--r--app/javascript/mastodon/locales/mk.json18
-rw-r--r--app/javascript/mastodon/locales/ml.json18
-rw-r--r--app/javascript/mastodon/locales/mr.json18
-rw-r--r--app/javascript/mastodon/locales/ms.json18
-rw-r--r--app/javascript/mastodon/locales/nl.json36
-rw-r--r--app/javascript/mastodon/locales/nn.json154
-rw-r--r--app/javascript/mastodon/locales/no.json18
-rw-r--r--app/javascript/mastodon/locales/oc.json18
-rw-r--r--app/javascript/mastodon/locales/pa.json18
-rw-r--r--app/javascript/mastodon/locales/pl.json22
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json18
-rw-r--r--app/javascript/mastodon/locales/pt-PT.json22
-rw-r--r--app/javascript/mastodon/locales/ro.json18
-rw-r--r--app/javascript/mastodon/locales/ru.json24
-rw-r--r--app/javascript/mastodon/locales/sa.json18
-rw-r--r--app/javascript/mastodon/locales/sc.json18
-rw-r--r--app/javascript/mastodon/locales/si.json18
-rw-r--r--app/javascript/mastodon/locales/sk.json30
-rw-r--r--app/javascript/mastodon/locales/sl.json22
-rw-r--r--app/javascript/mastodon/locales/sq.json22
-rw-r--r--app/javascript/mastodon/locales/sr-Latn.json18
-rw-r--r--app/javascript/mastodon/locales/sr.json18
-rw-r--r--app/javascript/mastodon/locales/sv.json18
-rw-r--r--app/javascript/mastodon/locales/szl.json18
-rw-r--r--app/javascript/mastodon/locales/ta.json18
-rw-r--r--app/javascript/mastodon/locales/tai.json18
-rw-r--r--app/javascript/mastodon/locales/te.json18
-rw-r--r--app/javascript/mastodon/locales/th.json26
-rw-r--r--app/javascript/mastodon/locales/tr.json36
-rw-r--r--app/javascript/mastodon/locales/tt.json18
-rw-r--r--app/javascript/mastodon/locales/ug.json18
-rw-r--r--app/javascript/mastodon/locales/uk.json22
-rw-r--r--app/javascript/mastodon/locales/ur.json18
-rw-r--r--app/javascript/mastodon/locales/vi.json22
-rw-r--r--app/javascript/mastodon/locales/zgh.json18
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json34
-rw-r--r--app/javascript/mastodon/locales/zh-HK.json18
-rw-r--r--app/javascript/mastodon/locales/zh-TW.json22
-rw-r--r--app/javascript/mastodon/reducers/filters.js11
-rw-r--r--app/javascript/mastodon/reducers/notifications.js10
-rw-r--r--app/javascript/mastodon/selectors/index.js19
-rw-r--r--app/javascript/mastodon/utils/filters.js16
-rw-r--r--app/javascript/mastodon/utils/icons.js13
-rw-r--r--app/javascript/styles/mastodon/components.scss25
-rw-r--r--app/lib/importer/statuses_index_importer.rb2
-rw-r--r--app/lib/request.rb18
-rw-r--r--app/models/concerns/account_interactions.rb10
-rw-r--r--app/models/custom_filter.rb28
-rw-r--r--app/models/custom_filter_status.rb37
-rw-r--r--app/models/email_domain_block.rb64
-rw-r--r--app/models/form/status_filter_batch_action.rb34
-rw-r--r--app/models/ip_block.rb1
-rw-r--r--app/models/user.rb2
-rw-r--r--app/presenters/filter_result_presenter.rb2
-rw-r--r--app/presenters/status_relationships_presenter.rb7
-rw-r--r--app/serializers/rest/filter_result_serializer.rb5
-rw-r--r--app/serializers/rest/filter_serializer.rb1
-rw-r--r--app/serializers/rest/filter_status_serializer.rb13
-rw-r--r--app/services/activitypub/process_account_service.rb2
-rw-r--r--app/services/app_sign_up_service.rb66
-rw-r--r--app/views/admin/accounts/index.html.haml2
-rw-r--r--app/views/admin/roles/_form.html.haml2
-rw-r--r--app/views/filters/_filter.html.haml9
-rw-r--r--app/views/filters/_filter_fields.html.haml7
-rw-r--r--app/views/filters/statuses/_status_filter.html.haml37
-rw-r--r--app/views/filters/statuses/index.html.haml38
-rw-r--r--boxfile.yml205
-rw-r--r--chart/.helmignore1
-rw-r--r--chart/Chart.lock16
-rw-r--r--chart/Chart.yaml14
-rw-r--r--chart/templates/_helpers.tpl50
-rw-r--r--chart/templates/configmap-env.yaml6
-rw-r--r--chart/templates/cronjob-media-remove.yaml18
-rw-r--r--chart/templates/deployment-sidekiq.yaml25
-rw-r--r--chart/templates/deployment-streaming.yaml10
-rw-r--r--chart/templates/deployment-web.yaml24
-rw-r--r--chart/templates/job-assets-precompile.yaml16
-rw-r--r--chart/templates/job-chewy-upgrade.yaml16
-rw-r--r--chart/templates/job-create-admin.yaml16
-rw-r--r--chart/templates/job-db-migrate.yaml16
-rw-r--r--chart/templates/secrets.yaml10
-rw-r--r--chart/values.yaml106
-rw-r--r--config/application.rb1
-rw-r--r--config/deploy.rb2
-rw-r--r--config/environments/production.rb2
-rw-r--r--config/initializers/http_client_proxy.rb17
-rw-r--r--config/locales/activerecord.de.yml11
-rw-r--r--config/locales/activerecord.es-MX.yml2
-rw-r--r--config/locales/activerecord.fi.yml19
-rw-r--r--config/locales/activerecord.gd.yml19
-rw-r--r--config/locales/activerecord.ja.yml6
-rw-r--r--config/locales/activerecord.ku.yml2
-rw-r--r--config/locales/activerecord.nn.yml32
-rw-r--r--config/locales/da.yml15
-rw-r--r--config/locales/de.yml82
-rw-r--r--config/locales/devise.en-GB.yml1
-rw-r--r--config/locales/devise.ku.yml6
-rw-r--r--config/locales/devise.nl.yml2
-rw-r--r--config/locales/devise.nn.yml50
-rw-r--r--config/locales/devise.tr.yml10
-rw-r--r--config/locales/doorkeeper.fi.yml8
-rw-r--r--config/locales/doorkeeper.ku.yml6
-rw-r--r--config/locales/doorkeeper.nn.yml33
-rw-r--r--config/locales/doorkeeper.th.yml2
-rw-r--r--config/locales/doorkeeper.tr.yml2
-rw-r--r--config/locales/en.yml15
-rw-r--r--config/locales/eo.yml71
-rw-r--r--config/locales/es-AR.yml15
-rw-r--r--config/locales/es-MX.yml70
-rw-r--r--config/locales/es.yml15
-rw-r--r--config/locales/fi.yml119
-rw-r--r--config/locales/gd.yml113
-rw-r--r--config/locales/gl.yml15
-rw-r--r--config/locales/he.yml109
-rw-r--r--config/locales/is.yml15
-rw-r--r--config/locales/ja.yml38
-rw-r--r--config/locales/ko.yml13
-rw-r--r--config/locales/ku.yml83
-rw-r--r--config/locales/lv.yml10
-rw-r--r--config/locales/nl.yml11
-rw-r--r--config/locales/nn.yml13
-rw-r--r--config/locales/pl.yml9
-rw-r--r--config/locales/ru.yml2
-rw-r--r--config/locales/simple_form.ca.yml2
-rw-r--r--config/locales/simple_form.da.yml2
-rw-r--r--config/locales/simple_form.de.yml27
-rw-r--r--config/locales/simple_form.el.yml2
-rw-r--r--config/locales/simple_form.en.yml2
-rw-r--r--config/locales/simple_form.eo.yml2
-rw-r--r--config/locales/simple_form.es-AR.yml2
-rw-r--r--config/locales/simple_form.es-MX.yml1
-rw-r--r--config/locales/simple_form.es.yml2
-rw-r--r--config/locales/simple_form.fi.yml34
-rw-r--r--config/locales/simple_form.gd.yml31
-rw-r--r--config/locales/simple_form.gl.yml2
-rw-r--r--config/locales/simple_form.hu.yml2
-rw-r--r--config/locales/simple_form.is.yml2
-rw-r--r--config/locales/simple_form.it.yml2
-rw-r--r--config/locales/simple_form.ko.yml2
-rw-r--r--config/locales/simple_form.ku.yml19
-rw-r--r--config/locales/simple_form.lv.yml2
-rw-r--r--config/locales/simple_form.nl.yml2
-rw-r--r--config/locales/simple_form.nn.yml18
-rw-r--r--config/locales/simple_form.pt-PT.yml2
-rw-r--r--config/locales/simple_form.ru.yml10
-rw-r--r--config/locales/simple_form.sl.yml2
-rw-r--r--config/locales/simple_form.sv.yml2
-rw-r--r--config/locales/simple_form.th.yml14
-rw-r--r--config/locales/simple_form.tr.yml2
-rw-r--r--config/locales/simple_form.uk.yml2
-rw-r--r--config/locales/simple_form.vi.yml2
-rw-r--r--config/locales/simple_form.zh-CN.yml2
-rw-r--r--config/locales/simple_form.zh-TW.yml2
-rw-r--r--config/locales/sk.yml31
-rw-r--r--config/locales/sl.yml19
-rw-r--r--config/locales/th.yml45
-rw-r--r--config/locales/tr.yml17
-rw-r--r--config/locales/uk.yml12
-rw-r--r--config/locales/vi.yml11
-rw-r--r--config/locales/zh-CN.yml15
-rw-r--r--config/locales/zh-TW.yml13
-rw-r--r--config/routes.rb11
-rw-r--r--db/migrate/20220808101323_create_custom_filter_statuses.rb12
-rw-r--r--db/schema.rb13
-rw-r--r--lib/mastodon/accounts_cli.rb4
-rw-r--r--lib/mastodon/media_cli.rb9
-rw-r--r--nanobox/nginx-local.conf92
-rw-r--r--nanobox/nginx-stream.conf.erb66
-rw-r--r--nanobox/nginx-web.conf.erb90
-rw-r--r--package.json20
-rw-r--r--spec/controllers/api/v1/filters/statuses_controller_spec.rb116
-rw-r--r--spec/controllers/api/v1/statuses_controller_spec.rb27
-rw-r--r--spec/fabricators/custom_filter_status_fabricator.rb4
-rw-r--r--spec/fabricators/webauthn_credential_fabricator.rb2
-rw-r--r--spec/models/email_domain_block_spec.rb27
-rw-r--r--spec/presenters/status_relationships_presenter_spec.rb27
-rw-r--r--spec/services/app_sign_up_service_spec.rb2
-rw-r--r--yarn.lock361
283 files changed, 5806 insertions, 1896 deletions
diff --git a/.env.nanobox b/.env.nanobox
deleted file mode 100644
index 51dfdbd58..000000000
--- a/.env.nanobox
+++ /dev/null
@@ -1,254 +0,0 @@
-# Service dependencies
-# You may set REDIS_URL instead for more advanced options
-REDIS_HOST=$DATA_REDIS_HOST
-REDIS_PORT=6379
-# REDIS_DB=0
-
-# You may set DATABASE_URL instead for more advanced options
-DB_HOST=$DATA_DB_HOST
-DB_USER=$DATA_DB_USER
-DB_NAME=gonano
-DB_PASS=$DATA_DB_PASS
-DB_PORT=5432
-
-# DATABASE_URL=postgresql://$DATA_DB_USER:$DATA_DB_PASS@$DATA_DB_HOST/gonano
-
-# Optional Elasticsearch configuration
-ES_ENABLED=true
-ES_HOST=$DATA_ELASTIC_HOST
-ES_PORT=9200
-
-BIND=0.0.0.0
-
-# Federation
-# Note: Changing LOCAL_DOMAIN at a later time will cause unwanted side effects, including breaking all existing federation.
-# LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com.
-LOCAL_DOMAIN=${APP_NAME}.nanoapp.io
-
-# Changing LOCAL_HTTPS in production is no longer supported. (Mastodon will always serve https:// links)
-
-# Use this only if you need to run mastodon on a different domain than the one used for federation.
-# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md
-# DO *NOT* USE THIS UNLESS YOU KNOW *EXACTLY* WHAT YOU ARE DOING.
-# WEB_DOMAIN=mastodon.example.com
-
-# Use this if you want to have several aliases handler@example1.com
-# handler@example2.com etc. for the same user. LOCAL_DOMAIN should not
-# be added. Comma separated values
-# ALTERNATE_DOMAINS=example1.com,example2.com
-
-# Application secrets
-# Generate each with the `rake secret` task (`nanobox run bundle exec rake secret`)
-SECRET_KEY_BASE=$SECRET_KEY_BASE
-OTP_SECRET=$OTP_SECRET
-
-# VAPID keys (used for push notifications)
-# You can generate the keys using the following command (first is the private key, second is the public one)
-# You should only generate this once per instance. If you later decide to change it, all push subscription will
-# be invalidated, requiring the users to access the website again to resubscribe.
-#
-# Generate with `rake mastodon:webpush:generate_vapid_key` task (`nanobox run bundle exec rake mastodon:webpush:generate_vapid_key`)
-#
-# For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html
-VAPID_PRIVATE_KEY=$VAPID_PRIVATE_KEY
-VAPID_PUBLIC_KEY=$VAPID_PUBLIC_KEY
-
-# Registrations
-# Single user mode will disable registrations and redirect frontpage to the first profile
-# SINGLE_USER_MODE=true
-# Prevent registrations with following e-mail domains
-# EMAIL_DOMAIN_BLACKLIST=example1.com|example2.de|etc
-# Only allow registrations with the following e-mail domains
-# EMAIL_DOMAIN_WHITELIST=example1.com|example2.de|etc
-
-# Optionally change default language
-# DEFAULT_LOCALE=de
-
-# E-mail configuration
-# Note: Mailgun and SparkPost (https://sparkpo.st/smtp) each have good free tiers
-# If you want to use an SMTP server without authentication (e.g local Postfix relay)
-# then set SMTP_AUTH_METHOD and SMTP_OPENSSL_VERIFY_MODE to 'none' and
-# *comment* SMTP_LOGIN and SMTP_PASSWORD (leaving them blank is not enough).
-SMTP_SERVER=$SMTP_SERVER
-SMTP_PORT=587
-SMTP_LOGIN=$SMTP_LOGIN
-SMTP_PASSWORD=$SMTP_PASSWORD
-SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
-#SMTP_REPLY_TO=
-#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
-#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
-#SMTP_AUTH_METHOD=plain
-#SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt
-#SMTP_OPENSSL_VERIFY_MODE=peer
-#SMTP_ENABLE_STARTTLS_AUTO=true
-#SMTP_TLS=true
-
-# Optional user upload path and URL (images, avatars). Default is :rails_root/public/system. If you set this variable, you are responsible for making your HTTP server (eg. nginx) serve these files.
-# PAPERCLIP_ROOT_PATH=/var/lib/mastodon/public-system
-# PAPERCLIP_ROOT_URL=/system
-
-# Optional asset host for multi-server setups
-# The asset host must allow cross origin request from WEB_DOMAIN or LOCAL_DOMAIN
-# if WEB_DOMAIN is not set. For example, the server may have the
-# following header field:
-# Access-Control-Allow-Origin: https://example.com/
-# CDN_HOST=https://assets.example.com
-
-# S3 (optional)
-# The attachment host must allow cross origin request from WEB_DOMAIN or
-# LOCAL_DOMAIN if WEB_DOMAIN is not set. For example, the server may have the
-# following header field:
-# Access-Control-Allow-Origin: https://192.168.1.123:9000/
-# S3_ENABLED=true
-# S3_BUCKET=
-# AWS_ACCESS_KEY_ID=
-# AWS_SECRET_ACCESS_KEY=
-# S3_REGION=
-# S3_PROTOCOL=http
-# S3_HOSTNAME=192.168.1.123:9000
-
-# S3 (Minio Config (optional) Please check Minio instance for details)
-# The attachment host must allow cross origin request - see the description
-# above.
-# S3_ENABLED=true
-# S3_BUCKET=
-# AWS_ACCESS_KEY_ID=
-# AWS_SECRET_ACCESS_KEY=
-# S3_REGION=
-# S3_PROTOCOL=https
-# S3_HOSTNAME=
-# 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.
-# SWIFT_ENABLED=true
-# SWIFT_USERNAME=
-# For Keystone V3, the value for SWIFT_TENANT should be the project name
-# SWIFT_TENANT=
-# SWIFT_PASSWORD=
-# Some OpenStack V3 providers require PROJECT_ID (optional)
-# SWIFT_PROJECT_ID=
-# Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid
-# issues with token rate-limiting during high load.
-# SWIFT_AUTH_URL=
-# SWIFT_CONTAINER=
-# SWIFT_OBJECT_URL=
-# SWIFT_REGION=
-# Defaults to 'default'
-# SWIFT_DOMAIN_NAME=
-# Defaults to 60 seconds. Set to 0 to disable
-# SWIFT_CACHE_TTL=
-
-# Optional alias for S3 (e.g. to serve files on a custom domain, possibly using Cloudfront or Cloudflare)
-# S3_ALIAS_HOST=
-
-# Streaming API integration
-# STREAMING_API_BASE_URL=
-
-# Advanced settings
-# If you need to use pgBouncer, you need to disable prepared statements:
-# PREPARED_STATEMENTS=false
-
-# Cluster number setting for streaming API server.
-# If you comment out following line, cluster number will be `numOfCpuCores - 1`.
-# STREAMING_CLUSTER_NUM=1
-
-# Docker mastodon user
-# If you use Docker, you may want to assign UID/GID manually.
-# UID=1000
-# GID=1000
-
-# LDAP authentication (optional)
-# LDAP_ENABLED=true
-# LDAP_HOST=localhost
-# LDAP_PORT=389
-# LDAP_METHOD=simple_tls
-# LDAP_BASE=
-# LDAP_BIND_DN=
-# LDAP_PASSWORD=
-# LDAP_UID=cn
-# LDAP_MAIL=mail
-# LDAP_SEARCH_FILTER=(|(%{uid}=%{email})(%{mail}=%{email}))
-# LDAP_UID_CONVERSION_ENABLED=true
-# LDAP_UID_CONVERSION_SEARCH=., -
-# LDAP_UID_CONVERSION_REPLACE=_
-
-# PAM authentication (optional)
-# PAM authentication uses for the email generation the "email" pam variable
-# and optional as fallback PAM_DEFAULT_SUFFIX
-# The pam environment variable "email" is provided by:
-# https://github.com/devkral/pam_email_extractor
-# PAM_ENABLED=true
-# Fallback email domain for email address generation (LOCAL_DOMAIN by default)
-# PAM_EMAIL_DOMAIN=example.com
-# Name of the pam service (pam "auth" section is evaluated)
-# PAM_DEFAULT_SERVICE=rpam
-# Name of the pam service used for checking if an user can register (pam "account" section is evaluated) (nil (disabled) by default)
-# PAM_CONTROLLED_SERVICE=rpam
-
-# Optional CAS authentication (cf. omniauth-cas) :
-# CAS_ENABLED=true
-# CAS_URL=https://sso.myserver.com/
-# CAS_HOST=sso.myserver.com/
-# CAS_PORT=443
-# CAS_SSL=true
-# CAS_VALIDATE_URL=
-# CAS_CALLBACK_URL=
-# CAS_LOGOUT_URL=
-# CAS_LOGIN_URL=
-# CAS_UID_FIELD='user'
-# CAS_CA_PATH=
-# CAS_DISABLE_SSL_VERIFICATION=false
-# CAS_UID_KEY='user'
-# CAS_NAME_KEY='name'
-# CAS_EMAIL_KEY='email'
-# CAS_NICKNAME_KEY='nickname'
-# CAS_FIRST_NAME_KEY='firstname'
-# CAS_LAST_NAME_KEY='lastname'
-# CAS_LOCATION_KEY='location'
-# CAS_IMAGE_KEY='image'
-# CAS_PHONE_KEY='phone'
-# CAS_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true
-
-# Optional SAML authentication (cf. omniauth-saml)
-# SAML_ENABLED=true
-# SAML_ACS_URL=http://localhost:3000/auth/auth/saml/callback
-# SAML_ISSUER=https://example.com
-# SAML_IDP_SSO_TARGET_URL=https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO
-# SAML_IDP_CERT=
-# SAML_IDP_CERT_FINGERPRINT=
-# SAML_NAME_IDENTIFIER_FORMAT=
-# SAML_CERT=
-# SAML_PRIVATE_KEY=
-# SAML_SECURITY_WANT_ASSERTION_SIGNED=true
-# SAML_SECURITY_WANT_ASSERTION_ENCRYPTED=true
-# SAML_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true
-# SAML_ATTRIBUTES_STATEMENTS_UID="urn:oid:0.9.2342.19200300.100.1.1"
-# SAML_ATTRIBUTES_STATEMENTS_EMAIL="urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
-# SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.16.840.1.113730.3.1.241"
-# SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME="urn:oid:2.5.4.42"
-# SAML_ATTRIBUTES_STATEMENTS_LAST_NAME="urn:oid:2.5.4.4"
-# SAML_UID_ATTRIBUTE="urn:oid:0.9.2342.19200300.100.1.1"
-# SAML_ATTRIBUTES_STATEMENTS_VERIFIED=
-# SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL=
-
-# Use HTTP proxy for outgoing request (optional)
-# http_proxy=http://gateway.local:8118
-# Access control for hidden service.
-# ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
diff --git a/.ruby-gemset b/.ruby-gemset
new file mode 100644
index 000000000..2b97bf65d
--- /dev/null
+++ b/.ruby-gemset
@@ -0,0 +1 @@
+mastodon
diff --git a/.ruby-version b/.ruby-version
index 75a22a26a..b0f2dcb32 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.0.3
+3.0.4
diff --git a/Dockerfile b/Dockerfile
index 6f04d400d..f440b4a17 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,7 +5,7 @@ SHELL ["/bin/bash", "-c"]
 RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
 
 # Install Node v16 (LTS)
-ENV NODE_VER="16.15.1"
+ENV NODE_VER="16.16.0"
 RUN ARCH= && \
     dpkgArch="$(dpkg --print-architecture)" && \
   case "${dpkgArch##*-}" in \
@@ -27,7 +27,7 @@ RUN ARCH= && \
 	mv node-v$NODE_VER-linux-$ARCH /opt/node
 
 # Install Ruby 3.0
-ENV RUBY_VER="3.0.3"
+ENV RUBY_VER="3.0.4"
 RUN apt-get update && \
   apt-get install -y --no-install-recommends build-essential \
     bison libyaml-dev libgdbm-dev libreadline-dev libjemalloc-dev \
diff --git a/Gemfile b/Gemfile
index 4cb162857..2c2837acc 100644
--- a/Gemfile
+++ b/Gemfile
@@ -51,7 +51,7 @@ gem 'ed25519', '~> 1.3'
 gem 'fast_blank', '~> 1.0'
 gem 'fastimage'
 gem 'hiredis', '~> 0.6'
-gem 'redis-namespace', '~> 1.8'
+gem 'redis-namespace', '~> 1.9'
 gem 'htmlentities', '~> 4.3'
 gem 'http', '~> 5.1'
 gem 'http_accept_language', '~> 2.1'
@@ -91,8 +91,8 @@ gem 'tty-prompt', '~> 0.23', require: false
 gem 'twitter-text', '~> 3.1.0'
 gem 'tzinfo-data', '~> 1.2022'
 gem 'webpacker', '~> 5.4'
-gem 'webpush', '~> 0.3'
-gem 'webauthn', '~> 3.0.0.alpha1'
+gem 'webpush', git: 'https://github.com/ClearlyClaire/webpush.git', ref: 'f14a4d52e201128b1b00245d11b6de80d6cfdcd9'
+gem 'webauthn', '~> 2.5'
 
 gem 'json-ld'
 gem 'json-ld-preloaded', '~> 3.2'
@@ -104,7 +104,7 @@ group :development, :test do
   gem 'fabrication', '~> 2.30'
   gem 'fuubar', '~> 2.5'
   gem 'i18n-tasks', '~> 1.0', require: false
-  gem 'pry-byebug', '~> 3.9'
+  gem 'pry-byebug', '~> 3.10'
   gem 'pry-rails', '~> 0.3'
   gem 'rspec-rails', '~> 5.1'
 end
@@ -121,7 +121,7 @@ group :test do
   gem 'rails-controller-testing', '~> 1.0'
   gem 'rspec-sidekiq', '~> 3.1'
   gem 'simplecov', '~> 0.21', require: false
-  gem 'webmock', '~> 3.14'
+  gem 'webmock', '~> 3.18'
   gem 'rspec_junit_formatter', '~> 0.5'
 end
 
@@ -136,7 +136,7 @@ group :development do
   gem 'memory_profiler'
   gem 'rubocop', '~> 1.30', require: false
   gem 'rubocop-rails', '~> 2.15', require: false
-  gem 'brakeman', '~> 5.2', require: false
+  gem 'brakeman', '~> 5.3', require: false
   gem 'bundler-audit', '~> 0.9', require: false
 
   gem 'capistrano', '~> 3.17'
diff --git a/Gemfile.lock b/Gemfile.lock
index c15eacad7..4a659d10e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,3 +1,12 @@
+GIT
+  remote: https://github.com/ClearlyClaire/webpush.git
+  revision: f14a4d52e201128b1b00245d11b6de80d6cfdcd9
+  ref: f14a4d52e201128b1b00245d11b6de80d6cfdcd9
+  specs:
+    webpush (0.3.8)
+      hkdf (~> 0.2)
+      jwt (~> 2.0)
+
 GEM
   remote: https://rubygems.org/
   specs:
@@ -69,7 +78,7 @@ GEM
     addressable (2.8.0)
       public_suffix (>= 2.0.2, < 5.0)
     aes_key_wrap (1.1.0)
-    airbrussh (1.4.0)
+    airbrussh (1.4.1)
       sshkit (>= 1.6.1, != 1.7.0)
     android_key_attestation (0.3.0)
     annotate (3.2.0)
@@ -79,7 +88,7 @@ GEM
     attr_encrypted (3.1.0)
       encryptor (~> 3.0.0)
     attr_required (1.0.1)
-    awrence (1.1.1)
+    awrence (1.2.1)
     aws-eventstream (1.2.0)
     aws-partitions (1.587.0)
     aws-sdk-core (3.130.2)
@@ -116,20 +125,20 @@ GEM
       ffi (~> 1.14)
     bootsnap (1.13.0)
       msgpack (~> 1.2)
-    brakeman (5.2.3)
+    brakeman (5.3.1)
     browser (4.2.0)
     brpoplpush-redis_script (0.1.2)
       concurrent-ruby (~> 1.0, >= 1.0.5)
       redis (>= 1.0, <= 5.0)
     builder (3.2.4)
-    bullet (7.0.2)
+    bullet (7.0.3)
       activesupport (>= 3.0.0)
       uniform_notifier (~> 1.11)
     bundler-audit (0.9.1)
       bundler (>= 1.2.0, < 3)
       thor (~> 1.0)
     byebug (11.1.3)
-    capistrano (3.17.0)
+    capistrano (3.17.1)
       airbrussh (>= 1.0.0)
       i18n
       rake (>= 10.0.0)
@@ -168,9 +177,9 @@ GEM
     color_diff (0.1)
     concurrent-ruby (1.1.10)
     connection_pool (2.2.5)
-    cose (1.0.0)
+    cose (1.2.1)
       cbor (~> 0.5.9)
-      openssl-signature_algorithm (~> 0.4.0)
+      openssl-signature_algorithm (~> 1.0)
     crack (0.4.5)
       rexml
     crass (1.0.6)
@@ -329,18 +338,18 @@ GEM
       activesupport (>= 4.2)
       aes_key_wrap
       bindata
-    json-ld (3.2.0)
+    json-ld (3.2.3)
       htmlentities (~> 4.3)
       json-canonicalization (~> 0.3)
       link_header (~> 0.0, >= 0.0.8)
       multi_json (~> 1.15)
       rack (~> 2.2)
-      rdf (~> 3.2)
+      rdf (~> 3.2, >= 3.2.9)
     json-ld-preloaded (3.2.0)
       json-ld (~> 3.2)
       rdf (~> 3.2)
     jsonapi-renderer (0.2.2)
-    jwt (2.2.2)
+    jwt (2.4.1)
     kaminari (1.2.2)
       activesupport (>= 4.1.0)
       kaminari-actionview (= 1.2.2)
@@ -403,9 +412,9 @@ GEM
     multi_json (1.15.0)
     multipart-post (2.1.1)
     net-ldap (0.17.1)
-    net-scp (3.0.0)
-      net-ssh (>= 2.6.5, < 7.0.0)
-    net-ssh (6.1.0)
+    net-scp (4.0.0.rc1)
+      net-ssh (>= 2.6.5, < 8.0.0)
+    net-ssh (7.0.1)
     nio4r (2.5.8)
     nokogiri (1.13.8)
       mini_portile2 (~> 2.8.0)
@@ -415,8 +424,8 @@ GEM
       concurrent-ruby (~> 1.0, >= 1.0.2)
       sidekiq (>= 3.5)
       statsd-ruby (~> 1.4, >= 1.4.0)
-    oj (3.13.18)
-    omniauth (1.9.1)
+    oj (3.13.20)
+    omniauth (1.9.2)
       hashie (>= 3.4.6)
       rack (>= 1.6.2, < 3)
     omniauth-cas (2.0.0)
@@ -439,8 +448,9 @@ GEM
       validate_email
       validate_url
       webfinger (>= 1.0.1)
-    openssl (2.2.0)
-    openssl-signature_algorithm (0.4.0)
+    openssl (3.0.0)
+    openssl-signature_algorithm (1.2.1)
+      openssl (> 2.0, < 3.1)
     orm_adapter (0.5.0)
     ox (2.14.11)
     parallel (1.22.1)
@@ -449,10 +459,10 @@ GEM
     parslet (2.0.0)
     pastel (0.8.0)
       tty-color (~> 0.5)
-    pg (1.4.2)
+    pg (1.4.3)
     pghero (2.8.3)
       activerecord (>= 5)
-    pkg-config (1.4.7)
+    pkg-config (1.4.9)
     posix-spawn (0.3.15)
     premailer (1.14.2)
       addressable
@@ -462,12 +472,12 @@ GEM
       actionmailer (>= 3)
       premailer (~> 1.7, >= 1.7.9)
     private_address_check (0.5.0)
-    pry (0.13.1)
+    pry (0.14.1)
       coderay (~> 1.1)
       method_source (~> 1.0)
-    pry-byebug (3.9.0)
+    pry-byebug (3.10.1)
       byebug (~> 11.0)
-      pry (~> 0.13.0)
+      pry (>= 0.13, < 0.15)
     pry-rails (0.3.9)
       pry (>= 0.10.4)
     public_suffix (4.0.7)
@@ -529,14 +539,14 @@ GEM
       thor (~> 1.0)
     rainbow (3.1.1)
     rake (13.0.6)
-    rdf (3.2.3)
+    rdf (3.2.9)
       link_header (~> 0.0, >= 0.0.8)
     rdf-normalize (0.5.0)
       rdf (~> 3.2)
     redcarpet (3.5.1)
     redis (4.5.1)
-    redis-namespace (1.8.2)
-      redis (>= 3.0.4)
+    redis-namespace (1.9.0)
+      redis (>= 4)
     regexp_parser (2.5.0)
     request_store (1.5.1)
       rack (>= 1.4)
@@ -602,12 +612,11 @@ GEM
     scenic (1.6.0)
       activerecord (>= 4.0.0)
       railties (>= 4.0.0)
-    securecompare (1.0.0)
     semantic_range (3.0.0)
-    sidekiq (6.5.1)
+    sidekiq (6.5.5)
       connection_pool (>= 2.2.2)
       rack (~> 2.0)
-      redis (>= 4.2.0)
+      redis (>= 4.5.0)
     sidekiq-bulk (0.2.0)
       sidekiq
     sidekiq-scheduler (4.0.2)
@@ -615,7 +624,7 @@ GEM
       rufus-scheduler (~> 3.2)
       sidekiq (>= 4)
       tilt (>= 1.4.0)
-    sidekiq-unique-jobs (7.1.26)
+    sidekiq-unique-jobs (7.1.27)
       brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
       concurrent-ruby (~> 1.0, >= 1.0.5)
       sidekiq (>= 5.0, < 8.0)
@@ -642,7 +651,7 @@ GEM
     sshkit (1.21.2)
       net-scp (>= 1.1.2)
       net-ssh (>= 2.8.0)
-    stackprof (0.2.20)
+    stackprof (0.2.21)
     statsd-ruby (1.5.0)
     stoplight (3.0.0)
     strong_migrations (0.7.9)
@@ -658,9 +667,10 @@ GEM
       climate_control (>= 0.0.3, < 1.0)
     thor (1.2.1)
     tilt (2.0.10)
-    tpm-key_attestation (0.9.0)
+    tpm-key_attestation (0.11.0)
       bindata (~> 2.4)
-      openssl-signature_algorithm (~> 0.4.0)
+      openssl (> 2.0, < 3.1)
+      openssl-signature_algorithm (~> 1.0)
     tty-color (0.6.0)
     tty-cursor (0.7.1)
     tty-prompt (0.23.1)
@@ -676,7 +686,7 @@ GEM
       unf (~> 0.1.0)
     tzinfo (2.0.5)
       concurrent-ruby (~> 1.0)
-    tzinfo-data (1.2022.1)
+    tzinfo-data (1.2022.3)
       tzinfo (>= 1.0.0)
     unf (0.1.4)
       unf_ext
@@ -691,20 +701,19 @@ GEM
       public_suffix
     warden (1.2.9)
       rack (>= 2.0.9)
-    webauthn (3.0.0.alpha1)
+    webauthn (2.5.2)
       android_key_attestation (~> 0.3.0)
       awrence (~> 1.1)
       bindata (~> 2.4)
       cbor (~> 0.5.9)
-      cose (~> 1.0)
-      openssl (~> 2.0)
+      cose (~> 1.1)
+      openssl (>= 2.2, < 3.1)
       safety_net_attestation (~> 0.4.0)
-      securecompare (~> 1.0)
-      tpm-key_attestation (~> 0.9.0)
+      tpm-key_attestation (~> 0.11.0)
     webfinger (1.2.0)
       activesupport
       httpclient (>= 2.4)
-    webmock (3.14.0)
+    webmock (3.18.1)
       addressable (>= 2.8.0)
       crack (>= 0.3.2)
       hashdiff (>= 0.4.0, < 2.0.0)
@@ -713,14 +722,11 @@ GEM
       rack-proxy (>= 0.6.1)
       railties (>= 5.2)
       semantic_range (>= 2.3.0)
-    webpush (0.3.8)
-      hkdf (~> 0.2)
-      jwt (~> 2.0)
     websocket-driver (0.7.5)
       websocket-extensions (>= 0.1.0)
     websocket-extensions (0.1.5)
     wisper (2.0.1)
-    xorcist (1.1.2)
+    xorcist (1.1.3)
     xpath (3.2.0)
       nokogiri (~> 1.8)
     zeitwerk (2.6.0)
@@ -738,7 +744,7 @@ DEPENDENCIES
   binding_of_caller (~> 1.0)
   blurhash (~> 0.1)
   bootsnap (~> 1.13.0)
-  brakeman (~> 5.2)
+  brakeman (~> 5.3)
   browser
   bullet (~> 7.0)
   bundler-audit (~> 0.9)
@@ -807,7 +813,7 @@ DEPENDENCIES
   posix-spawn
   premailer-rails
   private_address_check (~> 0.5)
-  pry-byebug (~> 3.9)
+  pry-byebug (~> 3.10)
   pry-rails (~> 0.3)
   puma (~> 5.6)
   pundit (~> 2.2)
@@ -821,7 +827,7 @@ DEPENDENCIES
   rdf-normalize (~> 0.5)
   redcarpet (~> 3.5)
   redis (~> 4.5)
-  redis-namespace (~> 1.8)
+  redis-namespace (~> 1.9)
   rexml (~> 3.2)
   rqrcode (~> 2.1)
   rspec-rails (~> 5.1)
@@ -848,8 +854,8 @@ DEPENDENCIES
   tty-prompt (~> 0.23)
   twitter-text (~> 3.1.0)
   tzinfo-data (~> 1.2022)
-  webauthn (~> 3.0.0.alpha1)
-  webmock (~> 3.14)
+  webauthn (~> 2.5)
+  webmock (~> 3.18)
   webpacker (~> 5.4)
-  webpush (~> 0.3)
+  webpush!
   xorcist (~> 1.1)
diff --git a/app/controllers/api/v1/filters/statuses_controller.rb b/app/controllers/api/v1/filters/statuses_controller.rb
new file mode 100644
index 000000000..b6bed306f
--- /dev/null
+++ b/app/controllers/api/v1/filters/statuses_controller.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+class Api::V1::Filters::StatusesController < Api::BaseController
+  before_action -> { doorkeeper_authorize! :read, :'read:filters' }, only: [:index, :show]
+  before_action -> { doorkeeper_authorize! :write, :'write:filters' }, except: [:index, :show]
+  before_action :require_user!
+
+  before_action :set_status_filters, only: :index
+  before_action :set_status_filter, only: [:show, :destroy]
+
+  def index
+    render json: @status_filters, each_serializer: REST::FilterStatusSerializer
+  end
+
+  def create
+    @status_filter = current_account.custom_filters.find(params[:filter_id]).statuses.create!(resource_params)
+
+    render json: @status_filter, serializer: REST::FilterStatusSerializer
+  end
+
+  def show
+    render json: @status_filter, serializer: REST::FilterStatusSerializer
+  end
+
+  def destroy
+    @status_filter.destroy!
+    render_empty
+  end
+
+  private
+
+  def set_status_filters
+    filter = current_account.custom_filters.includes(:statuses).find(params[:filter_id])
+    @status_filters = filter.statuses
+  end
+
+  def set_status_filter
+    @status_filter = CustomFilterStatus.includes(:custom_filter).where(custom_filter: { account: current_account }).find(params[:id])
+  end
+
+  def resource_params
+    params.permit(:status_id)
+  end
+end
diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb
index 1c0f360a9..486edcdcb 100644
--- a/app/controllers/auth/registrations_controller.rb
+++ b/app/controllers/auth/registrations_controller.rb
@@ -83,7 +83,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
   end
 
   def check_enabled_registrations
-    redirect_to root_path if single_user_mode? || omniauth_only? || !allowed_registrations?
+    redirect_to root_path if single_user_mode? || omniauth_only? || !allowed_registrations? || ip_blocked?
   end
 
   def allowed_registrations?
@@ -94,6 +94,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
     ENV['OMNIAUTH_ONLY'] == 'true'
   end
 
+  def ip_blocked?
+    IpBlock.where(severity: :sign_up_block).where('ip >>= ?', request.remote_ip.to_s).exists?
+  end
+
   def invite_code
     if params[:user]
       params[:user][:invite_code]
diff --git a/app/controllers/filters/statuses_controller.rb b/app/controllers/filters/statuses_controller.rb
new file mode 100644
index 000000000..cc493c22c
--- /dev/null
+++ b/app/controllers/filters/statuses_controller.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class Filters::StatusesController < ApplicationController
+  layout 'admin'
+
+  before_action :authenticate_user!
+  before_action :set_filter
+  before_action :set_status_filters
+  before_action :set_body_classes
+
+  PER_PAGE = 20
+
+  def index
+    @status_filter_batch_action = Form::StatusFilterBatchAction.new
+  end
+
+  def batch
+    @status_filter_batch_action = Form::StatusFilterBatchAction.new(status_filter_batch_action_params.merge(current_account: current_account, filter_id: params[:filter_id], type: action_from_button))
+    @status_filter_batch_action.save!
+  rescue ActionController::ParameterMissing
+    flash[:alert] = I18n.t('admin.statuses.no_status_selected')
+  ensure
+    redirect_to edit_filter_path(@filter)
+  end
+
+  private
+
+  def set_filter
+    @filter = current_account.custom_filters.find(params[:filter_id])
+  end
+
+  def set_status_filters
+    @status_filters = @filter.statuses.preload(:status).page(params[:page]).per(PER_PAGE)
+  end
+
+  def status_filter_batch_action_params
+    params.require(:form_status_filter_batch_action).permit(status_filter_ids: [])
+  end
+
+  def action_from_button
+    if params[:remove]
+      'remove'
+    end
+  end
+
+  def set_body_classes
+    @body_classes = 'admin'
+  end
+end
diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb
index 6d778312e..2ab3b0a74 100644
--- a/app/controllers/filters_controller.rb
+++ b/app/controllers/filters_controller.rb
@@ -9,7 +9,7 @@ class FiltersController < ApplicationController
   before_action :set_body_classes
 
   def index
-    @filters = current_account.custom_filters.includes(:keywords).order(:phrase)
+    @filters = current_account.custom_filters.includes(:keywords, :statuses).order(:phrase)
   end
 
   def new
diff --git a/app/javascript/flavours/glitch/actions/filters.js b/app/javascript/flavours/glitch/actions/filters.js
index 050b30322..9aa31028a 100644
--- a/app/javascript/flavours/glitch/actions/filters.js
+++ b/app/javascript/flavours/glitch/actions/filters.js
@@ -1,9 +1,24 @@
 import api from 'flavours/glitch/util/api';
+import { openModal } from './modal';
 
 export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
 export const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';
 export const FILTERS_FETCH_FAIL    = 'FILTERS_FETCH_FAIL';
 
+export const FILTERS_STATUS_CREATE_REQUEST = 'FILTERS_STATUS_CREATE_REQUEST';
+export const FILTERS_STATUS_CREATE_SUCCESS = 'FILTERS_STATUS_CREATE_SUCCESS';
+export const FILTERS_STATUS_CREATE_FAIL    = 'FILTERS_STATUS_CREATE_FAIL';
+
+export const FILTERS_CREATE_REQUEST = 'FILTERS_CREATE_REQUEST';
+export const FILTERS_CREATE_SUCCESS = 'FILTERS_CREATE_SUCCESS';
+export const FILTERS_CREATE_FAIL    = 'FILTERS_CREATE_FAIL';
+
+export const initAddFilter = (status, { contextType }) => dispatch =>
+  dispatch(openModal('FILTER', {
+    statusId: status?.get('id'),
+    contextType: contextType,
+  }));
+
 export const fetchFilters = () => (dispatch, getState) => {
   dispatch({
     type: FILTERS_FETCH_REQUEST,
@@ -11,7 +26,7 @@ export const fetchFilters = () => (dispatch, getState) => {
   });
 
   api(getState)
-    .get('/api/v1/filters')
+    .get('/api/v2/filters')
     .then(({ data }) => dispatch({
       type: FILTERS_FETCH_SUCCESS,
       filters: data,
@@ -24,3 +39,55 @@ export const fetchFilters = () => (dispatch, getState) => {
       skipAlert: true,
     }));
 };
+
+export const createFilterStatus = (params, onSuccess, onFail) => (dispatch, getState) => {
+  dispatch(createFilterStatusRequest());
+
+  api(getState).post(`/api/v1/filters/${params.filter_id}/statuses`, params).then(response => {
+    dispatch(createFilterStatusSuccess(response.data));
+    if (onSuccess) onSuccess();
+  }).catch(error => {
+    dispatch(createFilterStatusFail(error));
+    if (onFail) onFail();
+  });
+};
+
+export const createFilterStatusRequest = () => ({
+  type: FILTERS_STATUS_CREATE_REQUEST,
+});
+
+export const createFilterStatusSuccess = filter_status => ({
+  type: FILTERS_STATUS_CREATE_SUCCESS,
+  filter_status,
+});
+
+export const createFilterStatusFail = error => ({
+  type: FILTERS_STATUS_CREATE_FAIL,
+  error,
+});
+
+export const createFilter = (params, onSuccess, onFail) => (dispatch, getState) => {
+  dispatch(createFilterRequest());
+
+  api(getState).post('/api/v2/filters', params).then(response => {
+    dispatch(createFilterSuccess(response.data));
+    if (onSuccess) onSuccess(response.data);
+  }).catch(error => {
+    dispatch(createFilterFail(error));
+    if (onFail) onFail();
+  });
+};
+
+export const createFilterRequest = () => ({
+  type: FILTERS_CREATE_REQUEST,
+});
+
+export const createFilterSuccess = filter => ({
+  type: FILTERS_CREATE_SUCCESS,
+  filter,
+});
+
+export const createFilterFail = error => ({
+  type: FILTERS_CREATE_FAIL,
+  error,
+});
diff --git a/app/javascript/flavours/glitch/actions/importer/index.js b/app/javascript/flavours/glitch/actions/importer/index.js
index ec41fea6e..94d133b5f 100644
--- a/app/javascript/flavours/glitch/actions/importer/index.js
+++ b/app/javascript/flavours/glitch/actions/importer/index.js
@@ -5,6 +5,7 @@ export const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT';
 export const STATUS_IMPORT   = 'STATUS_IMPORT';
 export const STATUSES_IMPORT = 'STATUSES_IMPORT';
 export const POLLS_IMPORT    = 'POLLS_IMPORT';
+export const FILTERS_IMPORT  = 'FILTERS_IMPORT';
 
 function pushUnique(array, object) {
   if (array.every(element => element.id !== object.id)) {
@@ -28,6 +29,10 @@ export function importStatuses(statuses) {
   return { type: STATUSES_IMPORT, statuses };
 }
 
+export function importFilters(filters) {
+  return { type: FILTERS_IMPORT, filters };
+}
+
 export function importPolls(polls) {
   return { type: POLLS_IMPORT, polls };
 }
@@ -61,11 +66,16 @@ export function importFetchedStatuses(statuses) {
     const accounts = [];
     const normalStatuses = [];
     const polls = [];
+    const filters = [];
 
     function processStatus(status) {
       pushUnique(normalStatuses, normalizeStatus(status, getState().getIn(['statuses', status.id]), getState().get('local_settings')));
       pushUnique(accounts, status.account);
 
+      if (status.filtered) {
+        status.filtered.forEach(result => pushUnique(filters, result.filter));
+      }
+
       if (status.reblog && status.reblog.id) {
         processStatus(status.reblog);
       }
@@ -80,6 +90,7 @@ export function importFetchedStatuses(statuses) {
     dispatch(importPolls(polls));
     dispatch(importFetchedAccounts(accounts));
     dispatch(importStatuses(normalStatuses));
+    dispatch(importFilters(filters));
   };
 }
 
diff --git a/app/javascript/flavours/glitch/actions/importer/normalizer.js b/app/javascript/flavours/glitch/actions/importer/normalizer.js
index c6acdbdbb..9950a720b 100644
--- a/app/javascript/flavours/glitch/actions/importer/normalizer.js
+++ b/app/javascript/flavours/glitch/actions/importer/normalizer.js
@@ -42,6 +42,14 @@ export function normalizeAccount(account) {
   return account;
 }
 
+export function normalizeFilterResult(result) {
+  const normalResult = { ...result };
+
+  normalResult.filter = normalResult.filter.id;
+
+  return normalResult;
+}
+
 export function normalizeStatus(status, normalOldStatus, settings) {
   const normalStatus   = { ...status };
   normalStatus.account = status.account.id;
@@ -54,6 +62,10 @@ export function normalizeStatus(status, normalOldStatus, settings) {
     normalStatus.poll = status.poll.id;
   }
 
+  if (status.filtered) {
+    normalStatus.filtered = status.filtered.map(normalizeFilterResult);
+  }
+
   // Only calculate these values when status first encountered and
   // when the underlying values change. Otherwise keep the ones
   // already in the reducer
diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js
index 3993b1ea5..4581ebc36 100644
--- a/app/javascript/flavours/glitch/actions/notifications.js
+++ b/app/javascript/flavours/glitch/actions/notifications.js
@@ -12,10 +12,8 @@ import { saveSettings } from './settings';
 import { defineMessages } from 'react-intl';
 import { List as ImmutableList } from 'immutable';
 import { unescapeHTML } from 'flavours/glitch/util/html';
-import { getFiltersRegex } from 'flavours/glitch/selectors';
 import { usePendingItems as preferPendingItems } from 'flavours/glitch/util/initial_state';
 import compareId from 'flavours/glitch/util/compare_id';
-import { searchTextFromRawStatus } from 'flavours/glitch/actions/importer/normalizer';
 import { requestNotificationPermission } from 'flavours/glitch/util/notifications';
 
 export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
@@ -74,20 +72,17 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
     const showInColumn = activeFilter === 'all' ? getState().getIn(['settings', 'notifications', 'shows', notification.type], true) : activeFilter === notification.type;
     const showAlert    = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true);
     const playSound    = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true);
-    const filters      = getFiltersRegex(getState(), { contextType: 'notifications' });
 
     let filtered = false;
 
-    if (['mention', 'status'].includes(notification.type)) {
-      const dropRegex   = filters[0];
-      const regex       = filters[1];
-      const searchIndex = searchTextFromRawStatus(notification.status);
+    if (['mention', 'status'].includes(notification.type) && notification.status.filtered) {
+      const filters = notification.status.filtered.filter(result => result.filter.context.includes('notifications'));
 
-      if (dropRegex && dropRegex.test(searchIndex)) {
+      if (filters.some(result => result.filter.filter_action === 'hide')) {
         return;
       }
 
-      filtered = regex && regex.test(searchIndex);
+      filtered = filters.length > 0;
     }
 
     if (['follow_request'].includes(notification.type)) {
@@ -158,15 +153,22 @@ const excludeTypesFromFilter = filter => {
 
 const noOp = () => {};
 
-export function expandNotifications({ maxId } = {}, done = noOp) {
+let expandNotificationsController = new AbortController();
+
+export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) {
   return (dispatch, getState) => {
     const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']);
     const notifications = getState().get('notifications');
     const isLoadingMore = !!maxId;
 
     if (notifications.get('isLoading')) {
-      done();
-      return;
+      if (forceLoad) {
+        expandNotificationsController.abort();
+        expandNotificationsController = new AbortController();
+      } else {
+        done();
+        return;
+      }
     }
 
     const params = {
@@ -191,7 +193,7 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
 
     dispatch(expandNotificationsRequest(isLoadingMore));
 
-    api(getState).get('/api/v1/notifications', { params }).then(response => {
+    api(getState).get('/api/v1/notifications', { params, signal: expandNotificationsController.signal }).then(response => {
       const next = getLinks(response).refs.find(link => link.rel === 'next');
 
       dispatch(importFetchedAccounts(response.data.map(item => item.account)));
@@ -232,7 +234,7 @@ export function expandNotificationsFail(error, isLoadingMore) {
     type: NOTIFICATIONS_EXPAND_FAIL,
     error,
     skipLoading: !isLoadingMore,
-    skipAlert: !isLoadingMore,
+    skipAlert: !isLoadingMore || error.name === 'AbortError',
   };
 };
 
@@ -343,7 +345,7 @@ export function setFilter (filterType) {
       path: ['notifications', 'quickFilter', 'active'],
       value: filterType,
     });
-    dispatch(expandNotifications());
+    dispatch(expandNotifications({ forceLoad: true }));
     dispatch(saveSettings());
   };
 };
diff --git a/app/javascript/flavours/glitch/actions/statuses.js b/app/javascript/flavours/glitch/actions/statuses.js
index 1f223f22e..58c1d44a6 100644
--- a/app/javascript/flavours/glitch/actions/statuses.js
+++ b/app/javascript/flavours/glitch/actions/statuses.js
@@ -42,9 +42,9 @@ export function fetchStatusRequest(id, skipLoading) {
   };
 };
 
-export function fetchStatus(id) {
+export function fetchStatus(id, forceFetch = false) {
   return (dispatch, getState) => {
-    const skipLoading = getState().getIn(['statuses', id], null) !== null;
+    const skipLoading = !forceFetch && getState().getIn(['statuses', id], null) !== null;
 
     dispatch(fetchContext(id));
 
diff --git a/app/javascript/flavours/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js
index 90d6a0231..375728cb5 100644
--- a/app/javascript/flavours/glitch/actions/streaming.js
+++ b/app/javascript/flavours/glitch/actions/streaming.js
@@ -21,7 +21,6 @@ import {
   updateReaction as updateAnnouncementsReaction,
   deleteAnnouncement,
 } from './announcements';
-import { fetchFilters } from './filters';
 import { getLocale } from 'mastodon/locales';
 
 const { messages } = getLocale();
@@ -97,9 +96,6 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
         case 'conversation':
           dispatch(updateConversations(JSON.parse(data.payload)));
           break;
-        case 'filters_changed':
-          dispatch(fetchFilters());
-          break;
         case 'announcement':
           dispatch(updateAnnouncements(JSON.parse(data.payload)));
           break;
diff --git a/app/javascript/flavours/glitch/actions/tags.js b/app/javascript/flavours/glitch/actions/tags.js
index 3933da8ba..4016cf96f 100644
--- a/app/javascript/flavours/glitch/actions/tags.js
+++ b/app/javascript/flavours/glitch/actions/tags.js
@@ -75,18 +75,18 @@ export const unfollowHashtag = name => (dispatch, getState) => {
 };
 
 export const unfollowHashtagRequest = name => ({
-  type: HASHTAG_FETCH_REQUEST,
+  type: HASHTAG_UNFOLLOW_REQUEST,
   name,
 });
 
 export const unfollowHashtagSuccess = (name, tag) => ({
-  type: HASHTAG_FETCH_SUCCESS,
+  type: HASHTAG_UNFOLLOW_SUCCESS,
   name,
   tag,
 });
 
 export const unfollowHashtagFail = (name, error) => ({
-  type: HASHTAG_FETCH_FAIL,
+  type: HASHTAG_UNFOLLOW_FAIL,
   name,
   error,
 });
diff --git a/app/javascript/flavours/glitch/actions/timelines.js b/app/javascript/flavours/glitch/actions/timelines.js
index 0b36d8ac3..0d6f844b3 100644
--- a/app/javascript/flavours/glitch/actions/timelines.js
+++ b/app/javascript/flavours/glitch/actions/timelines.js
@@ -4,8 +4,7 @@ import api, { getLinks } from 'flavours/glitch/util/api';
 import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
 import compareId from 'flavours/glitch/util/compare_id';
 import { me, usePendingItems as preferPendingItems } from 'flavours/glitch/util/initial_state';
-import { getFiltersRegex } from 'flavours/glitch/selectors';
-import { searchTextFromRawStatus } from 'flavours/glitch/actions/importer/normalizer';
+import { toServerSideType } from 'flavours/glitch/util/filters';
 
 export const TIMELINE_UPDATE  = 'TIMELINE_UPDATE';
 export const TIMELINE_DELETE  = 'TIMELINE_DELETE';
@@ -40,14 +39,13 @@ export function updateTimeline(timeline, status, accept) {
       return;
     }
 
-    const filters   = getFiltersRegex(getState(), { contextType: timeline });
-    const dropRegex = filters[0];
-    const regex     = filters[1];
-    const text      = searchTextFromRawStatus(status);
-    let filtered    = false;
+    let filtered = false;
 
-    if (status.account.id !== me) {
-      filtered = (dropRegex && dropRegex.test(text)) || (regex && regex.test(text));
+    if (status.filtered) {
+      const contextType = toServerSideType(timeline);
+      const filters = status.filtered.filter(result => result.filter.context.includes(contextType));
+
+      filtered = filters.length > 0;
     }
 
     dispatch(importFetchedStatus(status));
diff --git a/app/javascript/flavours/glitch/components/icon_button.js b/app/javascript/flavours/glitch/components/icon_button.js
index be2468d68..9ff745355 100644
--- a/app/javascript/flavours/glitch/components/icon_button.js
+++ b/app/javascript/flavours/glitch/components/icon_button.js
@@ -139,17 +139,9 @@ export default class IconButton extends React.PureComponent {
       </React.Fragment>
     );
 
-    if (href) {
-      return (
-        <a
-          href={href}
-          aria-label={title}
-          title={title}
-          target='_blank'
-          rel='noopener noreferrer'
-          className={classes}
-          style={style}
-        >
+    if (href && !this.prop) {
+      contents = (
+        <a href={href} target='_blank' rel='noopener noreferrer'>
           {contents}
         </a>
       );
diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js
index 11c81765b..e238456c5 100644
--- a/app/javascript/flavours/glitch/components/status.js
+++ b/app/javascript/flavours/glitch/components/status.js
@@ -79,6 +79,7 @@ class Status extends ImmutablePureComponent {
     onOpenMedia: PropTypes.func,
     onOpenVideo: PropTypes.func,
     onBlock: PropTypes.func,
+    onAddFilter: PropTypes.func,
     onEmbed: PropTypes.func,
     onHeightChange: PropTypes.func,
     onToggleHidden: PropTypes.func,
@@ -455,8 +456,8 @@ class Status extends ImmutablePureComponent {
   }
 
   handleUnfilterClick = e => {
-    const { onUnfilter, status } = this.props;
-    onUnfilter(status.get('reblog') ? status.get('reblog') : status, () => this.setState({ forceFilter: false }));
+    this.setState({ forceFilter: false });
+    e.preventDefault();
   }
 
   handleFilterClick = () => {
@@ -557,8 +558,8 @@ class Status extends ImmutablePureComponent {
       );
     }
 
-    const filtered = (status.get('filtered') || status.getIn(['reblog', 'filtered'])) && settings.get('filtering_behavior') !== 'content_warning';
-    if (forceFilter === undefined ? filtered : forceFilter) {
+    const matchedFilters = status.get('matched_filters');
+    if (this.state.forceFilter === undefined ? matchedFilters : this.state.forceFilter) {
       const minHandlers = this.props.muted ? {} : {
         moveUp: this.handleHotkeyMoveUp,
         moveDown: this.handleHotkeyMoveDown,
@@ -567,13 +568,11 @@ class Status extends ImmutablePureComponent {
       return (
         <HotKeys handlers={minHandlers}>
           <div className='status__wrapper status__wrapper--filtered focusable' tabIndex='0' ref={this.handleRef}>
-            <FormattedMessage id='status.filtered' defaultMessage='Filtered' />
-            {settings.get('filtering_behavior') !== 'upstream' && ' '}
-            {settings.get('filtering_behavior') !== 'upstream' && (
-              <button className='status__wrapper--filtered__button' onClick={this.handleUnfilterClick}>
-                <FormattedMessage id='status.show_filter_reason' defaultMessage='(show why)' />
-              </button>
-            )}
+            <FormattedMessage id='status.filtered' defaultMessage='Filtered' />: {matchedFilters.join(', ')}.
+            {' '}
+            <button className='status__wrapper--filtered__button' onClick={this.handleUnfilterClick}>
+              <FormattedMessage id='status.show_filter_reason' defaultMessage='Show anyway' />
+            </button>
           </div>
         </HotKeys>
       );
@@ -625,6 +624,10 @@ class Status extends ImmutablePureComponent {
                 height={110}
                 cacheWidth={this.props.cacheMediaWidth}
                 deployPictureInPicture={this.handleDeployPictureInPicture}
+                sensitive={status.get('sensitive')}
+                blurhash={attachment.get('blurhash')}
+                visible={this.state.showMedia}
+                onToggleVisibility={this.handleToggleMediaVisibility}
               />
             )}
           </Bundle>,
@@ -785,11 +788,11 @@ class Status extends ImmutablePureComponent {
 
           {!isCollapsed || !(muted || !settings.getIn(['collapsed', 'show_action_bar'])) ? (
             <StatusActionBar
-              {...other}
               status={status}
               account={status.get('account')}
               showReplyCount={settings.get('show_reply_count')}
-              onFilter={this.handleFilterClick}
+              onFilter={matchedFilters ? this.handleFilterClick : null}
+              {...other}
             />
           ) : null}
           {notification ? (
diff --git a/app/javascript/flavours/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js
index 667afac5a..c0cd496ce 100644
--- a/app/javascript/flavours/glitch/components/status_action_bar.js
+++ b/app/javascript/flavours/glitch/components/status_action_bar.js
@@ -41,6 +41,7 @@ const messages = defineMessages({
   copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },
   hide: { id: 'status.hide', defaultMessage: 'Hide toot' },
   edited: { id: 'status.edited', defaultMessage: 'Edited {date}' },
+  filter: { id: 'status.filter', defaultMessage: 'Filter this post' },
 });
 
 export default @injectIntl
@@ -67,6 +68,7 @@ class StatusActionBar extends ImmutablePureComponent {
     onPin: PropTypes.func,
     onBookmark: PropTypes.func,
     onFilter: PropTypes.func,
+    onAddFilter: PropTypes.func,
     withDismiss: PropTypes.bool,
     showReplyCount: PropTypes.bool,
     scrollKey: PropTypes.string,
@@ -193,10 +195,14 @@ class StatusActionBar extends ImmutablePureComponent {
     }
   }
 
-  handleFilterClick = () => {
+  handleHideClick = () => {
     this.props.onFilter();
   }
 
+  handleFilterClick = () => {
+    this.props.onAddFilter(this.props.status);
+  }
+
   render () {
     const { status, intl, withDismiss, showReplyCount, scrollKey } = this.props;
 
@@ -238,6 +244,12 @@ class StatusActionBar extends ImmutablePureComponent {
       menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
       menu.push({ text: intl.formatMessage(messages.direct, { name: status.getIn(['account', 'username']) }), action: this.handleDirectClick });
       menu.push(null);
+
+      if (!this.props.onFilter) {
+        menu.push({ text: intl.formatMessage(messages.filter), action: this.handleFilterClick });
+        menu.push(null);
+      }
+
       menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
       menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
       menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
@@ -271,10 +283,6 @@ class StatusActionBar extends ImmutablePureComponent {
       <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} />
     );
 
-    const filterButton = status.get('filtered') && (
-      <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleFilterClick} />
-    );
-
     let replyButton = (
       <IconButton
         className='status__action-bar-button'
@@ -309,6 +317,10 @@ class StatusActionBar extends ImmutablePureComponent {
       reblogTitle = intl.formatMessage(messages.cannot_reblog);
     }
 
+    const filterButton = this.props.onFilter && (
+      <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleHideClick} />
+    );
+
     return (
       <div className='status__action-bar'>
         {replyButton}
@@ -316,6 +328,7 @@ class StatusActionBar extends ImmutablePureComponent {
         <IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} />
         {shareButton}
         <IconButton className='status__action-bar-button bookmark-icon' disabled={anonymousAccess} active={status.get('bookmarked')} pressed={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
+
         {filterButton}
 
         <div className='status__action-bar-dropdown'>
diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js
index 6c8f261e4..0ba2e712c 100644
--- a/app/javascript/flavours/glitch/containers/status_container.js
+++ b/app/javascript/flavours/glitch/containers/status_container.js
@@ -1,7 +1,7 @@
 import { connect } from 'react-redux';
 import Status from 'flavours/glitch/components/status';
 import { List as ImmutableList } from 'immutable';
-import { makeGetStatus, regexFromFilters, toServerSideType } from 'flavours/glitch/selectors';
+import { makeGetStatus } from 'flavours/glitch/selectors';
 import {
   replyCompose,
   mentionCompose,
@@ -25,6 +25,9 @@ import {
   revealStatus,
   editStatus
 } from 'flavours/glitch/actions/statuses';
+import {
+  initAddFilter,
+} from 'flavours/glitch/actions/filters';
 import { initMuteModal } from 'flavours/glitch/actions/mutes';
 import { initBlockModal } from 'flavours/glitch/actions/blocks';
 import { initReport } from 'flavours/glitch/actions/reports';
@@ -201,52 +204,14 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
     dispatch(initBlockModal(account));
   },
 
-  onUnfilter (status, onConfirm) {
-    dispatch((_, getState) => {
-      let state = getState();
-      const serverSideType = toServerSideType(contextType);
-      const enabledFilters = state.get('filters', ImmutableList()).filter(filter => filter.get('context').includes(serverSideType) && (filter.get('expires_at') === null || Date.parse(filter.get('expires_at')) > (new Date()))).toArray();
-      const searchIndex = status.get('search_index');
-      const matchingFilters = enabledFilters.filter(filter => regexFromFilters([filter]).test(searchIndex));
-      dispatch(openModal('CONFIRM', {
-        message: [
-          <FormattedMessage id='confirmations.unfilter' defaultMessage='Information about this filtered toot' />,
-          <div className='filtered-status-info'>
-            <Spoilers spoilerText={intl.formatMessage(messages.author)}>
-              <AccountContainer id={status.getIn(['account', 'id'])} />
-            </Spoilers>
-            <Spoilers spoilerText={intl.formatMessage(messages.matchingFilters, {count: matchingFilters.size})}>
-              <ul>
-                {matchingFilters.map(filter => (
-                  <li>
-                    {filter.get('phrase')}
-                    {!!filterEditLink && ' '}
-                    {!!filterEditLink && (
-                      <a
-                        target='_blank'
-                        className='filtered-status-edit-link'
-                        title={intl.formatMessage(messages.editFilter)}
-                        href={filterEditLink(filter.get('id'))}
-                      >
-                        <Icon id='pencil' />
-                      </a>
-                    )}
-                  </li>
-                ))}
-              </ul>
-            </Spoilers>
-          </div>
-        ],
-        confirm: intl.formatMessage(messages.unfilterConfirm),
-        onConfirm: onConfirm,
-      }));
-    });
-  },
-
   onReport (status) {
     dispatch(initReport(status.get('account'), status));
   },
 
+  onAddFilter (status) {
+    dispatch(initAddFilter(status, { contextType }));
+  },
+
   onMute (account) {
     dispatch(initMuteModal(account));
   },
diff --git a/app/javascript/flavours/glitch/features/audio/index.js b/app/javascript/flavours/glitch/features/audio/index.js
index ac0468f70..8fa64342e 100644
--- a/app/javascript/flavours/glitch/features/audio/index.js
+++ b/app/javascript/flavours/glitch/features/audio/index.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { defineMessages, injectIntl } from 'react-intl';
+import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
 import { formatTime } from 'flavours/glitch/features/video';
 import Icon from 'flavours/glitch/components/icon';
 import classNames from 'classnames';
@@ -8,6 +8,9 @@ import { throttle } from 'lodash';
 import { getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video';
 import { debounce } from 'lodash';
 import Visualizer from './visualizer';
+import { displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state';
+import Blurhash from 'flavours/glitch/components/blurhash';
+import { is } from 'immutable';
 
 const messages = defineMessages({
   play: { id: 'video.play', defaultMessage: 'Play' },
@@ -15,6 +18,7 @@ const messages = defineMessages({
   mute: { id: 'video.mute', defaultMessage: 'Mute sound' },
   unmute: { id: 'video.unmute', defaultMessage: 'Unmute sound' },
   download: { id: 'video.download', defaultMessage: 'Download file' },
+  hide: { id: 'audio.hide', defaultMessage: 'Hide audio' },
 });
 
 const TICK_SIZE = 10;
@@ -30,10 +34,14 @@ class Audio extends React.PureComponent {
     duration: PropTypes.number,
     width: PropTypes.number,
     height: PropTypes.number,
+    sensitive: PropTypes.bool,
     editable: PropTypes.bool,
     fullscreen: PropTypes.bool,
     intl: PropTypes.object.isRequired,
+    blurhash: PropTypes.string,
     cacheWidth: PropTypes.func,
+    visible: PropTypes.bool,
+    onToggleVisibility: PropTypes.func,
     backgroundColor: PropTypes.string,
     foregroundColor: PropTypes.string,
     accentColor: PropTypes.string,
@@ -53,6 +61,7 @@ class Audio extends React.PureComponent {
     muted: false,
     volume: 0.5,
     dragging: false,
+    revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
   };
 
   constructor (props) {
@@ -78,6 +87,8 @@ class Audio extends React.PureComponent {
       backgroundColor: this.props.backgroundColor,
       foregroundColor: this.props.foregroundColor,
       accentColor: this.props.accentColor,
+      sensitive: this.props.sensitive,
+      visible: this.props.visible,
     };
   }
 
@@ -132,6 +143,12 @@ class Audio extends React.PureComponent {
     }
   }
 
+  componentWillReceiveProps (nextProps) {
+    if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
+      this.setState({ revealed: nextProps.visible });
+    }
+  }
+
   componentWillUnmount () {
     window.removeEventListener('scroll', this.handleScroll);
     window.removeEventListener('resize', this.handleResize);
@@ -195,6 +212,14 @@ class Audio extends React.PureComponent {
     });
   }
 
+  toggleReveal = () => {
+    if (this.props.onToggleVisibility) {
+      this.props.onToggleVisibility();
+    } else {
+      this.setState({ revealed: !this.state.revealed });
+    }
+  }
+
   handleVolumeMouseDown = e => {
     document.addEventListener('mousemove', this.handleMouseVolSlide, true);
     document.addEventListener('mouseup', this.handleVolumeMouseUp, true);
@@ -439,13 +464,29 @@ class Audio extends React.PureComponent {
   }
 
   render () {
-    const { src, intl, alt, editable, autoPlay } = this.props;
-    const { paused, muted, volume, currentTime, duration, buffer, dragging } = this.state;
+    const { src, intl, alt, editable, autoPlay, sensitive, blurhash } = this.props;
+    const { paused, muted, volume, currentTime, duration, buffer, dragging, revealed } = this.state;
     const progress = Math.min((currentTime / duration) * 100, 100);
 
+    let warning;
+    if (sensitive) {
+      warning = <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />;
+    } else {
+      warning = <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />;
+    }
+
     return (
-      <div className={classNames('audio-player', { editable })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex='0' onKeyDown={this.handleKeyDown}>
-        <audio
+      <div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex='0' onKeyDown={this.handleKeyDown}>
+
+        <Blurhash
+          hash={blurhash}
+          className={classNames('media-gallery__preview', {
+            'media-gallery__preview--hidden': revealed,
+          })}
+          dummy={!useBlurhash}
+        />
+
+        {(revealed || editable) && <audio
           src={src}
           ref={this.setAudioRef}
           preload={autoPlay ? 'auto' : 'none'}
@@ -454,7 +495,7 @@ class Audio extends React.PureComponent {
           onProgress={this.handleProgress}
           onLoadedData={this.handleLoadedData}
           crossOrigin='anonymous'
-        />
+        />}
 
         <canvas
           role='button'
@@ -470,13 +511,19 @@ class Audio extends React.PureComponent {
           aria-label={alt}
         />
 
-        <img
+        <div className={classNames('spoiler-button', { 'spoiler-button--hidden': revealed || editable })}>
+          <button type='button' className='spoiler-button__overlay' onClick={this.toggleReveal}>
+            <span className='spoiler-button__overlay__label'>{warning}</span>
+          </button>
+        </div>
+
+        {(revealed || editable) && <img
           src={this.props.poster}
           alt=''
           width={(this._getRadius() - TICK_SIZE) * 2}
           height={(this._getRadius() - TICK_SIZE) * 2}
           style={{ position: 'absolute', left: this._getCX(), top: this._getCY(), transform: 'translate(-50%, -50%)', borderRadius: '50%', pointerEvents: 'none' }}
-        />
+        />}
 
         <div className='video-player__seek' onMouseDown={this.handleMouseDown} ref={this.setSeekRef}>
           <div className='video-player__seek__buffer' style={{ width: `${buffer}%` }} />
@@ -514,6 +561,7 @@ class Audio extends React.PureComponent {
             </div>
 
             <div className='video-player__buttons right'>
+              {!editable && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' fixedWidth /></button>}
               <a title={intl.formatMessage(messages.download)} aria-label={intl.formatMessage(messages.download)} className='video-player__download__icon player-button' href={this.props.src} download>
                 <Icon id={'download'} fixedWidth />
               </a>
diff --git a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js
index c8c503e58..035b0c0c3 100644
--- a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js
+++ b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.js
@@ -8,6 +8,7 @@ import spring from 'react-motion/lib/spring';
 import { supportsPassiveEvents } from 'detect-passive-events';
 import classNames from 'classnames';
 import { languages as preloadedLanguages } from 'flavours/glitch/util/initial_state';
+import { loupeIcon, deleteIcon } from 'flavours/glitch/util/icons';
 import fuzzysort from 'fuzzysort';
 
 const messages = defineMessages({
@@ -16,22 +17,6 @@ const messages = defineMessages({
   clear: { id: 'emoji_button.clear', defaultMessage: 'Clear' },
 });
 
-// Copied from emoji-mart for consistency with emoji picker and since
-// they don't export the icons in the package
-const icons = {
-  loupe: (
-    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'>
-      <path d='M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z' />
-    </svg>
-  ),
-
-  delete: (
-    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'>
-      <path d='M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z' />
-    </svg>
-  ),
-};
-
 const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
 
 class LanguageDropdownMenu extends React.PureComponent {
@@ -242,7 +227,7 @@ class LanguageDropdownMenu extends React.PureComponent {
           <div className={`language-dropdown__dropdown ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}>
             <div className='emoji-mart-search'>
               <input type='search' value={searchValue} onChange={this.handleSearchChange} onKeyDown={this.handleSearchKeyDown} placeholder={intl.formatMessage(messages.search)} autoFocus />
-              <button className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? icons.loupe : icons.delete}</button>
+              <button className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button>
             </div>
 
             <div className='language-dropdown__dropdown__results emoji-mart-scroll' role='listbox' ref={this.setListRef}>
diff --git a/app/javascript/flavours/glitch/features/filters/added_to_filter.js b/app/javascript/flavours/glitch/features/filters/added_to_filter.js
new file mode 100644
index 000000000..f777ca429
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/filters/added_to_filter.js
@@ -0,0 +1,102 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import { FormattedMessage } from 'react-intl';
+import { toServerSideType } from 'flavours/glitch/util/filters';
+import Button from 'flavours/glitch/components/button';
+import { connect } from 'react-redux';
+
+const mapStateToProps = (state, { filterId }) => ({
+  filter: state.getIn(['filters', filterId]),
+});
+
+export default @connect(mapStateToProps)
+class AddedToFilter extends React.PureComponent {
+
+  static propTypes = {
+    onClose: PropTypes.func.isRequired,
+    contextType: PropTypes.string,
+    filter: ImmutablePropTypes.map.isRequired,
+    dispatch: PropTypes.func.isRequired,
+  };
+
+  handleCloseClick = () => {
+    const { onClose } = this.props;
+    onClose();
+  };
+
+  render () {
+    const { filter, contextType } = this.props;
+
+    let expiredMessage = null;
+    if (filter.get('expires_at') && filter.get('expires_at') < new Date()) {
+      expiredMessage = (
+        <React.Fragment>
+          <h4 className='report-dialog-modal__subtitle'><FormattedMessage id='filter_modal.added.expired_title' defaultMessage='Expired filter!' /></h4>
+          <p className='report-dialog-modal__lead'>
+            <FormattedMessage
+              id='filter_modal.added.expired_explanation'
+              defaultMessage='This filter category has expired, you will need to change the expiration date for it to apply.'
+            />
+          </p>
+        </React.Fragment>
+      );
+    }
+
+    let contextMismatchMessage = null;
+    if (contextType && !filter.get('context').includes(toServerSideType(contextType))) {
+      contextMismatchMessage = (
+        <React.Fragment>
+          <h4 className='report-dialog-modal__subtitle'><FormattedMessage id='filter_modal.added.context_mismatch_title' defaultMessage='Context mismatch!' /></h4>
+          <p className='report-dialog-modal__lead'>
+            <FormattedMessage
+              id='filter_modal.added.context_mismatch_explanation'
+              defaultMessage='This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.'
+            />
+          </p>
+        </React.Fragment>
+      );
+    }
+
+    const settings_link = (
+      <a href={`/filters/${filter.get('id')}/edit`}>
+        <FormattedMessage
+          id='filter_modal.added.settings_link'
+          defaultMessage='settings page'
+        />
+      </a>
+    );
+
+    return (
+      <React.Fragment>
+        <h3 className='report-dialog-modal__title'><FormattedMessage id='filter_modal.added.title' defaultMessage='Filter added!' /></h3>
+        <p className='report-dialog-modal__lead'>
+          <FormattedMessage
+            id='filter_modal.added.short_explanation'
+            defaultMessage='This post has been added to the following filter category: {title}.'
+            values={{ title: filter.get('title') }}
+          />
+        </p>
+
+        {expiredMessage}
+        {contextMismatchMessage}
+
+        <h4 className='report-dialog-modal__subtitle'><FormattedMessage id='filter_modal.added.review_and_configure_title' defaultMessage='Filter settings' /></h4>
+        <p className='report-dialog-modal__lead'>
+          <FormattedMessage
+            id='filter_modal.added.review_and_configure'
+            defaultMessage='To review and further configure this filter category, go to the {settings_link}.'
+            values={{ settings_link }}
+          />
+        </p>
+
+        <div className='flex-spacer' />
+
+        <div className='report-dialog-modal__actions'>
+          <Button onClick={this.handleCloseClick}><FormattedMessage id='report.close' defaultMessage='Done' /></Button>
+        </div>
+      </React.Fragment>
+    );
+  }
+
+}
diff --git a/app/javascript/flavours/glitch/features/filters/select_filter.js b/app/javascript/flavours/glitch/features/filters/select_filter.js
new file mode 100644
index 000000000..5321dbb96
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/filters/select_filter.js
@@ -0,0 +1,192 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { toServerSideType } from 'flavours/glitch/util/filters';
+import { loupeIcon, deleteIcon } from 'flavours/glitch/util/icons';
+import Icon from 'flavours/glitch/components/icon';
+import fuzzysort from 'fuzzysort';
+
+const messages = defineMessages({
+  search: { id: 'filter_modal.select_filter.search', defaultMessage: 'Search or create' },
+  clear: { id: 'emoji_button.clear', defaultMessage: 'Clear' },
+});
+
+const mapStateToProps = (state, { contextType }) => ({
+  filters: Array.from(state.get('filters').values()).map((filter) => [
+    filter.get('id'),
+    filter.get('title'),
+    filter.get('keywords')?.map((keyword) => keyword.get('keyword')).join('\n'),
+    filter.get('expires_at') && filter.get('expires_at') < new Date(),
+    contextType && !filter.get('context').includes(toServerSideType(contextType)),
+  ]),
+});
+
+export default @connect(mapStateToProps)
+@injectIntl
+class SelectFilter extends React.PureComponent {
+
+  static propTypes = {
+    onSelectFilter: PropTypes.func.isRequired,
+    onNewFilter: PropTypes.func.isRequired,
+    filters: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.object)),
+    intl: PropTypes.object.isRequired,
+  };
+
+  state = {
+    searchValue: '',
+  };
+
+  search () {
+    const { filters } = this.props;
+    const { searchValue } = this.state;
+
+    if (searchValue === '') {
+      return filters;
+    }
+
+    return fuzzysort.go(searchValue, filters, {
+      keys: ['1', '2'],
+      limit: 5,
+      threshold: -10000,
+    }).map(result => result.obj);
+  }
+
+  renderItem = filter => {
+    let warning = null;
+    if (filter[3] || filter[4]) {
+      warning = (
+        <span className='language-dropdown__dropdown__results__item__common-name'>
+          (
+          {filter[3] && <FormattedMessage id='filter_modal.select_filter.expired' defaultMessage='expired' />}
+          {filter[3] && filter[4] && ', '}
+          {filter[4] && <FormattedMessage id='filter_modal.select_filter.context_mismatch' defaultMessage='does not apply to this context' />}
+          )
+        </span>
+      );
+    }
+
+    return (
+      <div key={filter[0]} role='button' tabIndex='0' data-index={filter[0]} className='language-dropdown__dropdown__results__item' onClick={this.handleItemClick} onKeyDown={this.handleKeyDown}>
+        <span className='language-dropdown__dropdown__results__item__native-name'>{filter[1]}</span> {warning}
+      </div>
+    );
+  }
+
+  renderCreateNew (name) {
+    return (
+      <div key='add-new-filter' role='button' tabIndex='0' className='language-dropdown__dropdown__results__item' onClick={this.handleNewFilterClick} onKeyDown={this.handleKeyDown}>
+        <Icon id='plus' fixedWidth /> <FormattedMessage id='filter_modal.select_filter.prompt_new' defaultMessage='New category: {name}' values={{ name }} />
+      </div>
+    );
+  }
+
+  handleSearchChange = ({ target }) => {
+    this.setState({ searchValue: target.value });
+  }
+
+  setListRef = c => {
+    this.listNode = c;
+  }
+
+  handleKeyDown = e => {
+    const index = Array.from(this.listNode.childNodes).findIndex(node => node === e.currentTarget);
+
+    let element = null;
+
+    switch(e.key) {
+    case ' ':
+    case 'Enter':
+      e.currentTarget.click();
+      break;
+    case 'ArrowDown':
+      element = this.listNode.childNodes[index + 1] || this.listNode.firstChild;
+      break;
+    case 'ArrowUp':
+      element = this.listNode.childNodes[index - 1] || this.listNode.lastChild;
+      break;
+    case 'Tab':
+      if (e.shiftKey) {
+        element = this.listNode.childNodes[index - 1] || this.listNode.lastChild;
+      } else {
+        element = this.listNode.childNodes[index + 1] || this.listNode.firstChild;
+      }
+      break;
+    case 'Home':
+      element = this.listNode.firstChild;
+      break;
+    case 'End':
+      element = this.listNode.lastChild;
+      break;
+    }
+
+    if (element) {
+      element.focus();
+      e.preventDefault();
+      e.stopPropagation();
+    }
+  }
+
+  handleSearchKeyDown = e => {
+    let element = null;
+
+    switch(e.key) {
+    case 'Tab':
+    case 'ArrowDown':
+      element = this.listNode.firstChild;
+
+      if (element) {
+        element.focus();
+        e.preventDefault();
+        e.stopPropagation();
+      }
+
+      break;
+    }
+  }
+
+  handleClear = () => {
+    this.setState({ searchValue: '' });
+  }
+
+  handleItemClick = e => {
+    const value = e.currentTarget.getAttribute('data-index');
+
+    e.preventDefault();
+
+    this.props.onSelectFilter(value);
+  }
+
+  handleNewFilterClick = e => {
+    e.preventDefault();
+
+    this.props.onNewFilter(this.state.searchValue);
+  };
+
+  render () {
+    const { intl } = this.props;
+
+    const { searchValue } = this.state;
+    const isSearching = searchValue !== '';
+    const results = this.search();
+
+    return (
+      <React.Fragment>
+        <h3 className='report-dialog-modal__title'><FormattedMessage id='filter_modal.select_filter.title' defaultMessage='Filter this post' /></h3>
+        <p className='report-dialog-modal__lead'><FormattedMessage id='filter_modal.select_filter.subtitle' defaultMessage='Use an existing category or create a new one' /></p>
+
+        <div className='emoji-mart-search'>
+          <input type='search' value={searchValue} onChange={this.handleSearchChange} onKeyDown={this.handleSearchKeyDown} placeholder={intl.formatMessage(messages.search)} autoFocus />
+          <button className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button>
+        </div>
+
+        <div className='language-dropdown__dropdown__results emoji-mart-scroll' role='listbox' ref={this.setListRef}>
+          {results.map(this.renderItem)}
+          {isSearching && this.renderCreateNew(searchValue) }
+        </div>
+
+      </React.Fragment>
+    );
+  }
+
+}
diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js
index ffa4e3409..333b73b45 100644
--- a/app/javascript/flavours/glitch/features/local_settings/page/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js
@@ -24,10 +24,6 @@ const messages = defineMessages({
   side_arm_copy: { id: 'settings.side_arm_reply_mode.copy', defaultMessage: 'Copy privacy setting of the toot being replied to' },
   side_arm_restrict: { id: 'settings.side_arm_reply_mode.restrict', defaultMessage: 'Restrict privacy setting to that of the toot being replied to' },
   regexp: { id: 'settings.content_warnings.regexp', defaultMessage: 'Regular expression' },
-  filters_drop: { id: 'settings.filtering_behavior.drop', defaultMessage: 'Hide filtered toots completely' },
-  filters_upstream: { id: 'settings.filtering_behavior.upstream', defaultMessage: 'Show "filtered" like vanilla Mastodon' },
-  filters_hide: { id: 'settings.filtering_behavior.hide', defaultMessage: 'Show "filtered" and add a button to display why' },
-  filters_cw: { id: 'settings.filtering_behavior.cw', defaultMessage: 'Still display the post, and add filtered words to content warning' },
   rewrite_mentions_no: { id: 'settings.rewrite_mentions_no', defaultMessage: 'Do not rewrite mentions' },
   rewrite_mentions_acct: { id: 'settings.rewrite_mentions_acct', defaultMessage: 'Rewrite with username and domain (when the account is remote)' },
   rewrite_mentions_username: { id: 'settings.rewrite_mentions_username', defaultMessage:  'Rewrite with username' },
@@ -358,25 +354,6 @@ class LocalSettingsPage extends React.PureComponent {
         </section>
       </div>
     ),
-    ({ intl, onChange, settings }) => (
-      <div className='glitch local-settings__page filters'>
-        <h1><FormattedMessage id='settings.filters' defaultMessage='Filters' /></h1>
-        <LocalSettingsPageItem
-          settings={settings}
-          item={['filtering_behavior']}
-          id='mastodon-settings--filters-behavior'
-          onChange={onChange}
-          options={[
-            { value: 'drop', message: intl.formatMessage(messages.filters_drop) },
-            { value: 'upstream', message: intl.formatMessage(messages.filters_upstream) },
-            { value: 'hide', message: intl.formatMessage(messages.filters_hide) },
-            { value: 'content_warning', message: intl.formatMessage(messages.filters_cw) }
-          ]}
-        >
-          <FormattedMessage id='settings.filtering_behavior' defaultMessage='Filtering behavior' />
-        </LocalSettingsPageItem>
-      </div>
-    ),
     ({ onChange, settings }) => (
       <div className='glitch local-settings__page collapsed'>
         <h1><FormattedMessage id='settings.collapsed_statuses' defaultMessage='Collapsed toots' /></h1>
diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
index 301a2add6..91dc5ba20 100644
--- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js
+++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
@@ -165,7 +165,11 @@ class DetailedStatus extends ImmutablePureComponent {
             backgroundColor={attachment.getIn(['meta', 'colors', 'background'])}
             foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])}
             accentColor={attachment.getIn(['meta', 'colors', 'accent'])}
+            sensitive={status.get('sensitive')}
+            visible={this.props.showMedia}
+            blurhash={attachment.get('blurhash')}
             height={150}
+            onToggleVisibility={this.props.onToggleMediaVisibility}
           />,
         );
         mediaIcons.push('music');
diff --git a/app/javascript/flavours/glitch/features/ui/components/filter_modal.js b/app/javascript/flavours/glitch/features/ui/components/filter_modal.js
new file mode 100644
index 000000000..d2482e733
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/ui/components/filter_modal.js
@@ -0,0 +1,134 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { fetchStatus } from 'flavours/glitch/actions/statuses';
+import { fetchFilters, createFilter, createFilterStatus } from 'flavours/glitch/actions/filters';
+import PropTypes from 'prop-types';
+import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import IconButton from 'flavours/glitch/components/icon_button';
+import SelectFilter from 'flavours/glitch/features/filters/select_filter';
+import AddedToFilter from 'flavours/glitch/features/filters/added_to_filter';
+
+const messages = defineMessages({
+  close: { id: 'lightbox.close', defaultMessage: 'Close' },
+});
+
+export default @connect(undefined)
+@injectIntl
+class FilterModal extends ImmutablePureComponent {
+
+  static propTypes = {
+    statusId: PropTypes.string.isRequired,
+    contextType: PropTypes.string,
+    dispatch: PropTypes.func.isRequired,
+    intl: PropTypes.object.isRequired,
+  };
+
+  state = {
+    step: 'select',
+    filterId: null,
+    isSubmitting: false,
+    isSubmitted: false,
+  };
+
+  handleNewFilterSuccess = (result) => {
+    this.handleSelectFilter(result.id);
+  };
+
+  handleSuccess = () => {
+    const { dispatch, statusId } = this.props;
+    dispatch(fetchStatus(statusId, true));
+    this.setState({ isSubmitting: false, isSubmitted: true, step: 'submitted' });
+  };
+
+  handleFail = () => {
+    this.setState({ isSubmitting: false });
+  };
+
+  handleNextStep = step => {
+    this.setState({ step });
+  };
+
+  handleSelectFilter = (filterId) => {
+    const { dispatch, statusId } = this.props;
+
+    this.setState({ isSubmitting: true, filterId });
+
+    dispatch(createFilterStatus({
+      filter_id: filterId,
+      status_id: statusId,
+    }, this.handleSuccess, this.handleFail));
+  };
+
+  handleNewFilter = (title) => {
+    const { dispatch } = this.props;
+
+    this.setState({ isSubmitting: true });
+
+    dispatch(createFilter({
+      title,
+      context: ['home', 'notifications', 'public', 'thread', 'account'],
+      action: 'warn',
+    }, this.handleNewFilterSuccess, this.handleFail));
+  };
+
+  componentDidMount () {
+    const { dispatch } = this.props;
+
+    dispatch(fetchFilters());
+  }
+
+  render () {
+    const {
+      intl,
+      statusId,
+      contextType,
+      onClose,
+    } = this.props;
+
+    const {
+      step,
+      filterId,
+    } = this.state;
+
+    let stepComponent;
+
+    switch(step) {
+    case 'select':
+      stepComponent = (
+        <SelectFilter
+          contextType={contextType}
+          onSelectFilter={this.handleSelectFilter}
+          onNewFilter={this.handleNewFilter}
+        />
+      );
+      break;
+    case 'create':
+      stepComponent = null;
+      break;
+    case 'submitted':
+      stepComponent = (
+        <AddedToFilter
+          contextType={contextType}
+          filterId={filterId}
+          statusId={statusId}
+          onClose={onClose}
+        />
+      );
+    }
+
+    return (
+      <div className='modal-root__modal report-dialog-modal'>
+        <div className='report-modal__target'>
+          <IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={20} />
+          <FormattedMessage id='filter_modal.title.status' defaultMessage='Filter a post' />
+        </div>
+
+        <div className='report-dialog-modal__container'>
+          {stepComponent}
+        </div>
+      </div>
+    );
+  }
+
+}
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 8f18d93b7..4df3a0dee 100644
--- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js
+++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js
@@ -26,6 +26,7 @@ import {
   ListAdder,
   PinnedAccountsEditor,
   CompareHistoryModal,
+  FilterModal,
 } from 'flavours/glitch/util/async-components';
 
 const MODAL_COMPONENTS = {
@@ -49,6 +50,7 @@ const MODAL_COMPONENTS = {
   'LIST_ADDER': ListAdder,
   'PINNED_ACCOUNTS_EDITOR': PinnedAccountsEditor,
   'COMPARE_HISTORY': CompareHistoryModal,
+  'FILTER': FilterModal,
 };
 
 export default class ModalRoot extends React.PureComponent {
diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js
index 099ffc69c..2be6d9478 100644
--- a/app/javascript/flavours/glitch/features/ui/index.js
+++ b/app/javascript/flavours/glitch/features/ui/index.js
@@ -10,7 +10,6 @@ import { debounce } from 'lodash';
 import { uploadCompose, resetCompose, changeComposeSpoilerness } from 'flavours/glitch/actions/compose';
 import { expandHomeTimeline } from 'flavours/glitch/actions/timelines';
 import { expandNotifications, notificationsSetVisibility } from 'flavours/glitch/actions/notifications';
-import { fetchFilters } from 'flavours/glitch/actions/filters';
 import { fetchRules } from 'flavours/glitch/actions/rules';
 import { clearHeight } from 'flavours/glitch/actions/height_cache';
 import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'flavours/glitch/actions/markers';
@@ -402,7 +401,7 @@ class UI extends React.Component {
     this.props.dispatch(fetchMarkers());
     this.props.dispatch(expandHomeTimeline());
     this.props.dispatch(expandNotifications());
-    setTimeout(() => this.props.dispatch(fetchFilters()), 500);
+
     setTimeout(() => this.props.dispatch(fetchRules()), 3000);
   }
 
diff --git a/app/javascript/flavours/glitch/reducers/filters.js b/app/javascript/flavours/glitch/reducers/filters.js
index 33f0c6732..f4f97cd3a 100644
--- a/app/javascript/flavours/glitch/reducers/filters.js
+++ b/app/javascript/flavours/glitch/reducers/filters.js
@@ -1,10 +1,43 @@
-import { FILTERS_FETCH_SUCCESS } from '../actions/filters';
-import { List as ImmutableList, fromJS } from 'immutable';
+import { FILTERS_IMPORT } from '../actions/importer';
+import { FILTERS_FETCH_SUCCESS, FILTERS_CREATE_SUCCESS } from '../actions/filters';
+import { Map as ImmutableMap, is, fromJS } from 'immutable';
 
-export default function filters(state = ImmutableList(), action) {
+const normalizeFilter = (state, filter) => {
+  const normalizedFilter = fromJS({
+    id: filter.id,
+    title: filter.title,
+    context: filter.context,
+    filter_action: filter.filter_action,
+    keywords: filter.keywords,
+    expires_at: filter.expires_at ? Date.parse(filter.expires_at) : null,
+  });
+
+  if (is(state.get(filter.id), normalizedFilter)) {
+    return state;
+  } else {
+    // Do not overwrite keywords when receiving a partial filter
+    return state.update(filter.id, ImmutableMap(), (old) => (
+      old.mergeWith(((old_value, new_value) => (new_value === undefined ? old_value : new_value)), normalizedFilter)
+    ));
+  }
+};
+
+const normalizeFilters = (state, filters) => {
+  filters.forEach(filter => {
+    state = normalizeFilter(state, filter);
+  });
+
+  return state;
+};
+
+export default function filters(state = ImmutableMap(), action) {
   switch(action.type) {
+  case FILTERS_CREATE_SUCCESS:
+    return normalizeFilter(state, action.filter);
   case FILTERS_FETCH_SUCCESS:
-    return fromJS(action.filters);
+    return normalizeFilters(ImmutableMap(), action.filters);
+  case FILTERS_IMPORT:
+    return normalizeFilters(state, action.filters);
   default:
     return state;
   }
diff --git a/app/javascript/flavours/glitch/reducers/local_settings.js b/app/javascript/flavours/glitch/reducers/local_settings.js
index 62ce29f0c..81ab1cb0d 100644
--- a/app/javascript/flavours/glitch/reducers/local_settings.js
+++ b/app/javascript/flavours/glitch/reducers/local_settings.js
@@ -21,7 +21,6 @@ const initialState = ImmutableMap({
   inline_preview_cards: true,
   hicolor_privacy_icons: false,
   show_content_type_choice: false,
-  filtering_behavior: 'hide',
   tag_misleading_links: true,
   rewrite_mentions: 'no',
   content_warnings : ImmutableMap({
diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js
index f538af7fa..51d7886d7 100644
--- a/app/javascript/flavours/glitch/reducers/notifications.js
+++ b/app/javascript/flavours/glitch/reducers/notifications.js
@@ -43,7 +43,7 @@ const initialState = ImmutableMap({
   unread: 0,
   lastReadId: '0',
   readMarkerId: '0',
-  isLoading: false,
+  isLoading: 0,
   cleaningMode: false,
   isTabVisible: true,
   browserSupport: false,
@@ -121,7 +121,7 @@ const expandNormalizedNotifications = (state, notifications, next, isLoadingRece
       }
     }
 
-    mutable.set('isLoading', false);
+    mutable.update('isLoading', (nbLoading) => nbLoading - 1);
   });
 };
 
@@ -249,10 +249,10 @@ export default function notifications(state = initialState, action) {
     return state.update('items', list => state.get('pendingItems').concat(list.take(40))).set('pendingItems', ImmutableList()).set('unread', 0);
   case NOTIFICATIONS_EXPAND_REQUEST:
   case NOTIFICATIONS_DELETE_MARKED_REQUEST:
-    return state.set('isLoading', true);
+    return state.set('isLoading', (nbLoading) => nbLoading + 1);
   case NOTIFICATIONS_DELETE_MARKED_FAIL:
   case NOTIFICATIONS_EXPAND_FAIL:
-    return state.set('isLoading', false);
+    return state.set('isLoading', (nbLoading) => nbLoading - 1);
   case NOTIFICATIONS_FILTER_SET:
     return state.set('items', ImmutableList()).set('hasMore', true);
   case NOTIFICATIONS_SCROLL_TOP:
@@ -270,8 +270,6 @@ export default function notifications(state = initialState, action) {
   case FOLLOW_REQUEST_AUTHORIZE_SUCCESS:
   case FOLLOW_REQUEST_REJECT_SUCCESS:
     return filterNotifications(state, [action.id], 'follow_request');
-  case ACCOUNT_MUTE_SUCCESS:
-    return action.relationship.muting_notifications ? filterNotifications(state, [action.relationship.id]) : state;
   case NOTIFICATIONS_CLEAR:
     return state.set('items', ImmutableList()).set('pendingItems', ImmutableList()).set('hasMore', false);
   case TIMELINE_DELETE:
@@ -289,7 +287,7 @@ export default function notifications(state = initialState, action) {
     return markForDelete(state, action.id, action.yes);
 
   case NOTIFICATIONS_DELETE_MARKED_SUCCESS:
-    return deleteMarkedNotifs(state).set('isLoading', false);
+    return deleteMarkedNotifs(state).set('isLoading', (nbLoading) => nbLoading - 1);
 
   case NOTIFICATIONS_ENTER_CLEARING_MODE:
     st = state.set('cleaningMode', action.yes);
diff --git a/app/javascript/flavours/glitch/selectors/index.js b/app/javascript/flavours/glitch/selectors/index.js
index d9aa8f140..377805f16 100644
--- a/app/javascript/flavours/glitch/selectors/index.js
+++ b/app/javascript/flavours/glitch/selectors/index.js
@@ -1,6 +1,7 @@
 import escapeTextContentForBrowser from 'escape-html';
 import { createSelector } from 'reselect';
-import { List as ImmutableList, is } from 'immutable';
+import { List as ImmutableList } from 'immutable';
+import { toServerSideType } from 'flavours/glitch/util/filters';
 import { me } from 'flavours/glitch/util/initial_state';
 
 const getAccountBase         = (state, id) => state.getIn(['accounts', id], null);
@@ -21,69 +22,15 @@ export const makeGetAccount = () => {
   });
 };
 
-export const toServerSideType = columnType => {
-  switch (columnType) {
-  case 'home':
-  case 'notifications':
-  case 'public':
-  case 'thread':
-  case 'account':
-    return columnType;
-  default:
-    if (columnType.indexOf('list:') > -1) {
-      return 'home';
-    } else {
-      return 'public'; // community, account, hashtag
-    }
-  }
-};
-
-const escapeRegExp = string =>
-  string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
-
-export const regexFromFilters = filters => {
-  if (filters.size === 0) {
-    return null;
-  }
-
-  return new RegExp(filters.map(filter => {
-    let expr = escapeRegExp(filter.get('phrase'));
-
-    if (filter.get('whole_word')) {
-      if (/^[\w]/.test(expr)) {
-        expr = `\\b${expr}`;
-      }
-
-      if (/[\w]$/.test(expr)) {
-        expr = `${expr}\\b`;
-      }
-    }
-
-    return expr;
-  }).join('|'), 'i');
-};
-
-// Memoize the filter regexps for each valid server contextType
-const makeGetFiltersRegex = () => {
-  let memo = {};
-
-  return (state, { contextType }) => {
-    if (!contextType) return ImmutableList();
+const getFilters = (state, { contextType }) => {
+  if (!contextType) return null;
 
-    const serverSideType = toServerSideType(contextType);
-    const filters = state.get('filters', ImmutableList()).filter(filter => filter.get('context').includes(serverSideType) && (filter.get('expires_at') === null || Date.parse(filter.get('expires_at')) > (new Date())));
+  const serverSideType = toServerSideType(contextType);
+  const now = new Date();
 
-    if (!memo[serverSideType] || !is(memo[serverSideType].filters, filters)) {
-      const dropRegex = regexFromFilters(filters.filter(filter => filter.get('irreversible')));
-      const regex = regexFromFilters(filters);
-      memo[serverSideType] = { filters: filters, results: [dropRegex, regex] };
-    }
-    return memo[serverSideType].results;
-  };
+  return state.get('filters').filter((filter) => filter.get('context').includes(serverSideType) && (filter.get('expires_at') === null || filter.get('expires_at') > now));
 };
 
-export const getFiltersRegex = makeGetFiltersRegex();
-
 export const makeGetStatus = () => {
   return createSelector(
     [
@@ -91,60 +38,37 @@ export const makeGetStatus = () => {
       (state, { id }) => state.getIn(['statuses', state.getIn(['statuses', id, 'reblog'])]),
       (state, { id }) => state.getIn(['accounts', state.getIn(['statuses', id, 'account'])]),
       (state, { id }) => state.getIn(['accounts', state.getIn(['statuses', state.getIn(['statuses', id, 'reblog']), 'account'])]),
-      (state, _) => state.getIn(['local_settings', 'filtering_behavior']),
-      (state, _) => state.get('filters', ImmutableList()),
-      (_, { contextType }) => contextType,
-      getFiltersRegex,
+      getFilters,
     ],
 
-    (statusBase, statusReblog, accountBase, accountReblog, filteringBehavior, filters, contextType, filtersRegex) => {
+    (statusBase, statusReblog, accountBase, accountReblog, filters) => {
       if (!statusBase) {
         return null;
       }
 
-      const dropRegex = (accountReblog || accountBase).get('id') !== me && filtersRegex[0];
-
-      if (dropRegex && dropRegex.test(statusBase.get('reblog') ? statusReblog.get('search_index') : statusBase.get('search_index'))) {
-        return null;
-      }
-
-      const regex  = (accountReblog || accountBase).get('id') !== me && filtersRegex[1];
       let filtered = false;
+      if ((accountReblog || accountBase).get('id') !== me && filters) {
+        let filterResults = statusReblog?.get('filtered') || statusBase.get('filtered') || ImmutableList();
+        if (filterResults.some((result) => filters.getIn([result.get('filter'), 'filter_action']) === 'hide')) {
+          return null;
+        }
+        filterResults = filterResults.filter(result => filters.has(result.get('filter')));
+        if (!filterResults.isEmpty()) {
+          filtered = filterResults.map(result => filters.getIn([result.get('filter'), 'title']));
+        }
+      }
 
       if (statusReblog) {
-        filtered     = regex && regex.test(statusReblog.get('search_index'));
         statusReblog = statusReblog.set('account', accountReblog);
-        statusReblog = statusReblog.set('filtered', filtered);
+        statusReblog = statusReblog.set('matched_filters', filtered);
       } else {
         statusReblog = null;
       }
 
-      filtered = filtered || regex && regex.test(statusBase.get('search_index'));
-
-      if (filtered && filteringBehavior === 'drop') {
-        return null;
-      } else if (filtered && filteringBehavior === 'content_warning') {
-        let spoilerText = (statusReblog || statusBase).get('spoiler_text', '');
-        const searchIndex = (statusReblog || statusBase).get('search_index');
-        const serverSideType = toServerSideType(contextType);
-        const enabledFilters = filters.filter(filter => filter.get('context').includes(serverSideType) && (filter.get('expires_at') === null || Date.parse(filter.get('expires_at')) > (new Date()))).toArray();
-        const matchingFilters = enabledFilters.filter(filter => {
-          const regexp = regexFromFilters([filter]);
-          return regexp.test(searchIndex) && !regexp.test(spoilerText);
-        });
-        if (statusReblog) {
-          statusReblog = statusReblog.set('spoiler_text', matchingFilters.map(filter => filter.get('phrase')).concat([spoilerText]).filter(cw => !!cw).join(', '));
-          statusReblog = statusReblog.update('spoilerHtml', '', spoilerText => matchingFilters.map(filter => escapeTextContentForBrowser(filter.get('phrase'))).concat([spoilerText]).filter(cw => !!cw).join(', '));
-        } else {
-          statusBase = statusBase.set('spoiler_text', matchingFilters.map(filter => filter.get('phrase')).concat([spoilerText]).filter(cw => !!cw).join(', '));
-          statusBase = statusBase.update('spoilerHtml', '', spoilerText => matchingFilters.map(filter => escapeTextContentForBrowser(filter.get('phrase'))).concat([spoilerText]).filter(cw => !!cw).join(', '));
-        }
-      }
-
       return statusBase.withMutations(map => {
         map.set('reblog', statusReblog);
         map.set('account', accountBase);
-        map.set('filtered', filtered);
+        map.set('matched_filters', filtered);
       });
     },
   );
diff --git a/app/javascript/flavours/glitch/styles/components/media.scss b/app/javascript/flavours/glitch/styles/components/media.scss
index 8a551be73..9776e2265 100644
--- a/app/javascript/flavours/glitch/styles/components/media.scss
+++ b/app/javascript/flavours/glitch/styles/components/media.scss
@@ -389,6 +389,13 @@
     height: 100%;
   }
 
+  &.inactive {
+    audio,
+    .video-player__controls {
+      visibility: hidden;
+    }
+  }
+
   .video-player__volume::before,
   .video-player__seek::before {
     background: currentColor;
diff --git a/app/javascript/flavours/glitch/styles/components/modal.scss b/app/javascript/flavours/glitch/styles/components/modal.scss
index 90e0da02a..e95bea0d7 100644
--- a/app/javascript/flavours/glitch/styles/components/modal.scss
+++ b/app/javascript/flavours/glitch/styles/components/modal.scss
@@ -583,6 +583,16 @@
     line-height: 22px;
     color: lighten($inverted-text-color, 16%);
     margin-bottom: 30px;
+
+    a {
+      text-decoration: none;
+      color: $inverted-text-color;
+      font-weight: 500;
+
+      &:hover {
+        text-decoration: underline;
+      }
+    }
   }
 
   &__actions {
@@ -730,6 +740,14 @@
     background: transparent;
     margin: 15px 0;
   }
+
+  .emoji-mart-search {
+    padding-right: 10px;
+  }
+
+  .emoji-mart-search-icon {
+    right: 10px + 5px;
+  }
 }
 
 .report-modal__container {
diff --git a/app/javascript/flavours/glitch/util/async-components.js b/app/javascript/flavours/glitch/util/async-components.js
index 8c9630eea..86bb7be36 100644
--- a/app/javascript/flavours/glitch/util/async-components.js
+++ b/app/javascript/flavours/glitch/util/async-components.js
@@ -177,3 +177,7 @@ export function FollowRecommendations () {
 export function CompareHistoryModal () {
   return import(/*webpackChunkName: "flavours/glitch/async/compare_history_modal" */'flavours/glitch/features/ui/components/compare_history_modal');
 }
+
+export function FilterModal () {
+  return import(/*webpackChunkName: "flavours/glitch/async/filter_modal" */'flavours/glitch/features/ui/components/filter_modal');
+}
diff --git a/app/javascript/flavours/glitch/util/filters.js b/app/javascript/flavours/glitch/util/filters.js
new file mode 100644
index 000000000..97b433a99
--- /dev/null
+++ b/app/javascript/flavours/glitch/util/filters.js
@@ -0,0 +1,16 @@
+export const toServerSideType = columnType => {
+  switch (columnType) {
+  case 'home':
+  case 'notifications':
+  case 'public':
+  case 'thread':
+  case 'account':
+    return columnType;
+  default:
+    if (columnType.indexOf('list:') > -1) {
+      return 'home';
+    } else {
+      return 'public'; // community, account, hashtag
+    }
+  }
+};
diff --git a/app/javascript/flavours/glitch/util/icons.js b/app/javascript/flavours/glitch/util/icons.js
new file mode 100644
index 000000000..be566032e
--- /dev/null
+++ b/app/javascript/flavours/glitch/util/icons.js
@@ -0,0 +1,13 @@
+// Copied from emoji-mart for consistency with emoji picker and since
+// they don't export the icons in the package
+export const loupeIcon = (
+  <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'>
+    <path d='M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z' />
+  </svg>
+);
+
+export const deleteIcon = (
+  <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'>
+    <path d='M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z' />
+  </svg>
+);
diff --git a/app/javascript/mastodon/actions/filters.js b/app/javascript/mastodon/actions/filters.js
new file mode 100644
index 000000000..76326802e
--- /dev/null
+++ b/app/javascript/mastodon/actions/filters.js
@@ -0,0 +1,93 @@
+import api from '../api';
+import { openModal } from './modal';
+
+export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
+export const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';
+export const FILTERS_FETCH_FAIL    = 'FILTERS_FETCH_FAIL';
+
+export const FILTERS_STATUS_CREATE_REQUEST = 'FILTERS_STATUS_CREATE_REQUEST';
+export const FILTERS_STATUS_CREATE_SUCCESS = 'FILTERS_STATUS_CREATE_SUCCESS';
+export const FILTERS_STATUS_CREATE_FAIL    = 'FILTERS_STATUS_CREATE_FAIL';
+
+export const FILTERS_CREATE_REQUEST = 'FILTERS_CREATE_REQUEST';
+export const FILTERS_CREATE_SUCCESS = 'FILTERS_CREATE_SUCCESS';
+export const FILTERS_CREATE_FAIL    = 'FILTERS_CREATE_FAIL';
+
+export const initAddFilter = (status, { contextType }) => dispatch =>
+  dispatch(openModal('FILTER', {
+    statusId: status?.get('id'),
+    contextType: contextType,
+  }));
+
+export const fetchFilters = () => (dispatch, getState) => {
+  dispatch({
+    type: FILTERS_FETCH_REQUEST,
+    skipLoading: true,
+  });
+
+  api(getState)
+    .get('/api/v2/filters')
+    .then(({ data }) => dispatch({
+      type: FILTERS_FETCH_SUCCESS,
+      filters: data,
+      skipLoading: true,
+    }))
+    .catch(err => dispatch({
+      type: FILTERS_FETCH_FAIL,
+      err,
+      skipLoading: true,
+      skipAlert: true,
+    }));
+};
+
+export const createFilterStatus = (params, onSuccess, onFail) => (dispatch, getState) => {
+  dispatch(createFilterStatusRequest());
+
+  api(getState).post(`/api/v1/filters/${params.filter_id}/statuses`, params).then(response => {
+    dispatch(createFilterStatusSuccess(response.data));
+    if (onSuccess) onSuccess();
+  }).catch(error => {
+    dispatch(createFilterStatusFail(error));
+    if (onFail) onFail();
+  });
+};
+
+export const createFilterStatusRequest = () => ({
+  type: FILTERS_STATUS_CREATE_REQUEST,
+});
+
+export const createFilterStatusSuccess = filter_status => ({
+  type: FILTERS_STATUS_CREATE_SUCCESS,
+  filter_status,
+});
+
+export const createFilterStatusFail = error => ({
+  type: FILTERS_STATUS_CREATE_FAIL,
+  error,
+});
+
+export const createFilter = (params, onSuccess, onFail) => (dispatch, getState) => {
+  dispatch(createFilterRequest());
+
+  api(getState).post('/api/v2/filters', params).then(response => {
+    dispatch(createFilterSuccess(response.data));
+    if (onSuccess) onSuccess(response.data);
+  }).catch(error => {
+    dispatch(createFilterFail(error));
+    if (onFail) onFail();
+  });
+};
+
+export const createFilterRequest = () => ({
+  type: FILTERS_CREATE_REQUEST,
+});
+
+export const createFilterSuccess = filter => ({
+  type: FILTERS_CREATE_SUCCESS,
+  filter,
+});
+
+export const createFilterFail = error => ({
+  type: FILTERS_CREATE_FAIL,
+  error,
+});
diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js
index 3c42f71da..d4588db2c 100644
--- a/app/javascript/mastodon/actions/notifications.js
+++ b/app/javascript/mastodon/actions/notifications.js
@@ -141,15 +141,22 @@ const excludeTypesFromFilter = filter => {
 
 const noOp = () => {};
 
-export function expandNotifications({ maxId } = {}, done = noOp) {
+let expandNotificationsController = new AbortController();
+
+export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) {
   return (dispatch, getState) => {
     const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']);
     const notifications = getState().get('notifications');
     const isLoadingMore = !!maxId;
 
     if (notifications.get('isLoading')) {
-      done();
-      return;
+      if (forceLoad) {
+        expandNotificationsController.abort();
+        expandNotificationsController = new AbortController();
+      } else {
+        done();
+        return;
+      }
     }
 
     const params = {
@@ -174,7 +181,7 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
 
     dispatch(expandNotificationsRequest(isLoadingMore));
 
-    api(getState).get('/api/v1/notifications', { params }).then(response => {
+    api(getState).get('/api/v1/notifications', { params, signal: expandNotificationsController.signal }).then(response => {
       const next = getLinks(response).refs.find(link => link.rel === 'next');
 
       dispatch(importFetchedAccounts(response.data.map(item => item.account)));
@@ -215,7 +222,7 @@ export function expandNotificationsFail(error, isLoadingMore) {
     type: NOTIFICATIONS_EXPAND_FAIL,
     error,
     skipLoading: !isLoadingMore,
-    skipAlert: !isLoadingMore,
+    skipAlert: !isLoadingMore || error.name === 'AbortError',
   };
 };
 
@@ -243,7 +250,7 @@ export function setFilter (filterType) {
       path: ['notifications', 'quickFilter', 'active'],
       value: filterType,
     });
-    dispatch(expandNotifications());
+    dispatch(expandNotifications({ forceLoad: true }));
     dispatch(saveSettings());
   };
 };
diff --git a/app/javascript/mastodon/actions/statuses.js b/app/javascript/mastodon/actions/statuses.js
index adc24eabf..32a4f1f85 100644
--- a/app/javascript/mastodon/actions/statuses.js
+++ b/app/javascript/mastodon/actions/statuses.js
@@ -42,9 +42,9 @@ export function fetchStatusRequest(id, skipLoading) {
   };
 };
 
-export function fetchStatus(id) {
+export function fetchStatus(id, forceFetch = false) {
   return (dispatch, getState) => {
-    const skipLoading = getState().getIn(['statuses', id], null) !== null;
+    const skipLoading = !forceFetch && getState().getIn(['statuses', id], null) !== null;
 
     dispatch(fetchContext(id));
 
diff --git a/app/javascript/mastodon/actions/tags.js b/app/javascript/mastodon/actions/tags.js
index 216e5b541..37e79d4cb 100644
--- a/app/javascript/mastodon/actions/tags.js
+++ b/app/javascript/mastodon/actions/tags.js
@@ -75,18 +75,18 @@ export const unfollowHashtag = name => (dispatch, getState) => {
 };
 
 export const unfollowHashtagRequest = name => ({
-  type: HASHTAG_FETCH_REQUEST,
+  type: HASHTAG_UNFOLLOW_REQUEST,
   name,
 });
 
 export const unfollowHashtagSuccess = (name, tag) => ({
-  type: HASHTAG_FETCH_SUCCESS,
+  type: HASHTAG_UNFOLLOW_SUCCESS,
   name,
   tag,
 });
 
 export const unfollowHashtagFail = (name, error) => ({
-  type: HASHTAG_FETCH_FAIL,
+  type: HASHTAG_UNFOLLOW_FAIL,
   name,
   error,
 });
diff --git a/app/javascript/mastodon/components/icon_button.js b/app/javascript/mastodon/components/icon_button.js
index 81743a1db..47945c475 100644
--- a/app/javascript/mastodon/components/icon_button.js
+++ b/app/javascript/mastodon/components/icon_button.js
@@ -131,17 +131,9 @@ export default class IconButton extends React.PureComponent {
       </React.Fragment>
     );
 
-    if (href) {
-      return (
-        <a
-          href={href}
-          aria-label={title}
-          title={title}
-          target='_blank'
-          rel='noopener noreferrer'
-          className={classes}
-          style={style}
-        >
+    if (href && !this.prop) {
+      contents = (
+        <a href={href} target='_blank' rel='noopener noreferrer'>
           {contents}
         </a>
       );
diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js
index 238a0d734..6fc132bf5 100644
--- a/app/javascript/mastodon/components/status.js
+++ b/app/javascript/mastodon/components/status.js
@@ -80,6 +80,7 @@ class Status extends ImmutablePureComponent {
     onOpenMedia: PropTypes.func,
     onOpenVideo: PropTypes.func,
     onBlock: PropTypes.func,
+    onAddFilter: PropTypes.func,
     onEmbed: PropTypes.func,
     onHeightChange: PropTypes.func,
     onToggleHidden: PropTypes.func,
@@ -409,6 +410,10 @@ class Status extends ImmutablePureComponent {
                 height={110}
                 cacheWidth={this.props.cacheMediaWidth}
                 deployPictureInPicture={pictureInPicture.get('available') ? this.handleDeployPictureInPicture : undefined}
+                sensitive={status.get('sensitive')}
+                blurhash={attachment.get('blurhash')}
+                visible={this.state.showMedia}
+                onToggleVisibility={this.handleToggleMediaVisibility}
               />
             )}
           </Bundle>
@@ -511,7 +516,7 @@ class Status extends ImmutablePureComponent {
 
             {media}
 
-            <StatusActionBar scrollKey={scrollKey} status={status} account={account} onFilter={matchedFilters && this.handleFilterClick} {...other} />
+            <StatusActionBar scrollKey={scrollKey} status={status} account={account} onFilter={matchedFilters ? this.handleFilterClick : null} {...other} />
           </div>
         </div>
       </HotKeys>
diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js
index d44da482d..4b384e6e5 100644
--- a/app/javascript/mastodon/components/status_action_bar.js
+++ b/app/javascript/mastodon/components/status_action_bar.js
@@ -44,6 +44,7 @@ const messages = defineMessages({
   unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
   unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
   unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
+  filter: { id: 'status.filter', defaultMessage: 'Filter this post' },
 });
 
 const mapStateToProps = (state, { status }) => ({
@@ -80,6 +81,7 @@ class StatusActionBar extends ImmutablePureComponent {
     onPin: PropTypes.func,
     onBookmark: PropTypes.func,
     onFilter: PropTypes.func,
+    onAddFilter: PropTypes.func,
     withDismiss: PropTypes.bool,
     withCounters: PropTypes.bool,
     scrollKey: PropTypes.string,
@@ -211,8 +213,8 @@ class StatusActionBar extends ImmutablePureComponent {
     this.props.onMuteConversation(this.props.status);
   }
 
-  handleFilter = () => {
-    this.props.onFilter();
+  handleFilterClick = () => {
+    this.props.onAddFilter(this.props.status);
   }
 
   handleCopy = () => {
@@ -235,7 +237,7 @@ class StatusActionBar extends ImmutablePureComponent {
   }
 
 
-  handleFilterClick = () => {
+  handleHideClick = () => {
     this.props.onFilter();
   }
 
@@ -294,6 +296,12 @@ class StatusActionBar extends ImmutablePureComponent {
         menu.push({ text: intl.formatMessage(messages.block, { name: account.get('username') }), action: this.handleBlockClick });
       }
 
+      if (!this.props.onFilter) {
+        menu.push(null);
+        menu.push({ text: intl.formatMessage(messages.filter), action: this.handleFilterClick });
+        menu.push(null);
+      }
+
       menu.push({ text: intl.formatMessage(messages.report, { name: account.get('username') }), action: this.handleReport });
 
       if (account.get('acct') !== account.get('username')) {
@@ -343,7 +351,7 @@ class StatusActionBar extends ImmutablePureComponent {
     );
 
     const filterButton = this.props.onFilter && (
-      <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleFilterClick} />
+      <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleHideClick} />
     );
 
     return (
diff --git a/app/javascript/mastodon/containers/status_container.js b/app/javascript/mastodon/containers/status_container.js
index ef0aca13a..28698b082 100644
--- a/app/javascript/mastodon/containers/status_container.js
+++ b/app/javascript/mastodon/containers/status_container.js
@@ -34,6 +34,9 @@ import {
   blockDomain,
   unblockDomain,
 } from '../actions/domain_blocks';
+import {
+  initAddFilter,
+} from '../actions/filters';
 import { initMuteModal } from '../actions/mutes';
 import { initBlockModal } from '../actions/blocks';
 import { initBoostModal } from '../actions/boosts';
@@ -66,7 +69,7 @@ const makeMapStateToProps = () => {
   return mapStateToProps;
 };
 
-const mapDispatchToProps = (dispatch, { intl }) => ({
+const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
 
   onReply (status, router) {
     dispatch((_, getState) => {
@@ -176,6 +179,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
     dispatch(initReport(status.get('account'), status));
   },
 
+  onAddFilter (status) {
+    dispatch(initAddFilter(status, { contextType }));
+  },
+
   onMute (account) {
     dispatch(initMuteModal(account));
   },
diff --git a/app/javascript/mastodon/features/audio/index.js b/app/javascript/mastodon/features/audio/index.js
index c47f55dd1..00854d0e4 100644
--- a/app/javascript/mastodon/features/audio/index.js
+++ b/app/javascript/mastodon/features/audio/index.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { defineMessages, injectIntl } from 'react-intl';
+import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
 import { formatTime } from 'mastodon/features/video';
 import Icon from 'mastodon/components/icon';
 import classNames from 'classnames';
@@ -8,6 +8,9 @@ import { throttle } from 'lodash';
 import { getPointerPosition, fileNameFromURL } from 'mastodon/features/video';
 import { debounce } from 'lodash';
 import Visualizer from './visualizer';
+import { displayMedia, useBlurhash } from '../../initial_state';
+import Blurhash from '../../components/blurhash';
+import { is } from 'immutable';
 
 const messages = defineMessages({
   play: { id: 'video.play', defaultMessage: 'Play' },
@@ -15,6 +18,7 @@ const messages = defineMessages({
   mute: { id: 'video.mute', defaultMessage: 'Mute sound' },
   unmute: { id: 'video.unmute', defaultMessage: 'Unmute sound' },
   download: { id: 'video.download', defaultMessage: 'Download file' },
+  hide: { id: 'audio.hide', defaultMessage: 'Hide audio' },
 });
 
 const TICK_SIZE = 10;
@@ -30,10 +34,14 @@ class Audio extends React.PureComponent {
     duration: PropTypes.number,
     width: PropTypes.number,
     height: PropTypes.number,
+    sensitive: PropTypes.bool,
     editable: PropTypes.bool,
     fullscreen: PropTypes.bool,
     intl: PropTypes.object.isRequired,
+    blurhash: PropTypes.string,
     cacheWidth: PropTypes.func,
+    visible: PropTypes.bool,
+    onToggleVisibility: PropTypes.func,
     backgroundColor: PropTypes.string,
     foregroundColor: PropTypes.string,
     accentColor: PropTypes.string,
@@ -53,6 +61,7 @@ class Audio extends React.PureComponent {
     muted: false,
     volume: 0.5,
     dragging: false,
+    revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
   };
 
   constructor (props) {
@@ -78,6 +87,8 @@ class Audio extends React.PureComponent {
       backgroundColor: this.props.backgroundColor,
       foregroundColor: this.props.foregroundColor,
       accentColor: this.props.accentColor,
+      sensitive: this.props.sensitive,
+      visible: this.props.visible,
     };
   }
 
@@ -126,6 +137,12 @@ class Audio extends React.PureComponent {
     }
   }
 
+  componentWillReceiveProps (nextProps) {
+    if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
+      this.setState({ revealed: nextProps.visible });
+    }
+  }
+
   componentWillUnmount () {
     window.removeEventListener('scroll', this.handleScroll);
     window.removeEventListener('resize', this.handleResize);
@@ -189,6 +206,14 @@ class Audio extends React.PureComponent {
     });
   }
 
+  toggleReveal = () => {
+    if (this.props.onToggleVisibility) {
+      this.props.onToggleVisibility();
+    } else {
+      this.setState({ revealed: !this.state.revealed });
+    }
+  }
+
   handleVolumeMouseDown = e => {
     document.addEventListener('mousemove', this.handleMouseVolSlide, true);
     document.addEventListener('mouseup', this.handleVolumeMouseUp, true);
@@ -433,13 +458,29 @@ class Audio extends React.PureComponent {
   }
 
   render () {
-    const { src, intl, alt, editable, autoPlay } = this.props;
-    const { paused, muted, volume, currentTime, duration, buffer, dragging } = this.state;
+    const { src, intl, alt, editable, autoPlay, sensitive, blurhash } = this.props;
+    const { paused, muted, volume, currentTime, duration, buffer, dragging, revealed } = this.state;
     const progress = Math.min((currentTime / duration) * 100, 100);
 
+    let warning;
+    if (sensitive) {
+      warning = <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />;
+    } else {
+      warning = <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />;
+    }
+
     return (
-      <div className={classNames('audio-player', { editable })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex='0' onKeyDown={this.handleKeyDown}>
-        <audio
+      <div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex='0' onKeyDown={this.handleKeyDown}>
+
+        <Blurhash
+          hash={blurhash}
+          className={classNames('media-gallery__preview', {
+            'media-gallery__preview--hidden': revealed,
+          })}
+          dummy={!useBlurhash}
+        />
+
+        {(revealed || editable) && <audio
           src={src}
           ref={this.setAudioRef}
           preload={autoPlay ? 'auto' : 'none'}
@@ -448,7 +489,7 @@ class Audio extends React.PureComponent {
           onProgress={this.handleProgress}
           onLoadedData={this.handleLoadedData}
           crossOrigin='anonymous'
-        />
+        />}
 
         <canvas
           role='button'
@@ -464,13 +505,19 @@ class Audio extends React.PureComponent {
           aria-label={alt}
         />
 
-        <img
+        <div className={classNames('spoiler-button', { 'spoiler-button--hidden': revealed || editable })}>
+          <button type='button' className='spoiler-button__overlay' onClick={this.toggleReveal}>
+            <span className='spoiler-button__overlay__label'>{warning}</span>
+          </button>
+        </div>
+
+        {(revealed || editable) && <img
           src={this.props.poster}
           alt=''
           width={(this._getRadius() - TICK_SIZE) * 2}
           height={(this._getRadius() - TICK_SIZE) * 2}
           style={{ position: 'absolute', left: this._getCX(), top: this._getCY(), transform: 'translate(-50%, -50%)', borderRadius: '50%', pointerEvents: 'none' }}
-        />
+        />}
 
         <div className='video-player__seek' onMouseDown={this.handleMouseDown} ref={this.setSeekRef}>
           <div className='video-player__seek__buffer' style={{ width: `${buffer}%` }} />
@@ -508,6 +555,7 @@ class Audio extends React.PureComponent {
             </div>
 
             <div className='video-player__buttons right'>
+              {!editable && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' fixedWidth /></button>}
               <a title={intl.formatMessage(messages.download)} aria-label={intl.formatMessage(messages.download)} className='video-player__download__icon player-button' href={this.props.src} download>
                 <Icon id={'download'} fixedWidth />
               </a>
diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.js b/app/javascript/mastodon/features/compose/components/language_dropdown.js
index d76490c77..0af3db7a4 100644
--- a/app/javascript/mastodon/features/compose/components/language_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/language_dropdown.js
@@ -8,6 +8,7 @@ import spring from 'react-motion/lib/spring';
 import { supportsPassiveEvents } from 'detect-passive-events';
 import classNames from 'classnames';
 import { languages as preloadedLanguages } from 'mastodon/initial_state';
+import { loupeIcon, deleteIcon } from 'mastodon/utils/icons';
 import fuzzysort from 'fuzzysort';
 
 const messages = defineMessages({
@@ -16,22 +17,6 @@ const messages = defineMessages({
   clear: { id: 'emoji_button.clear', defaultMessage: 'Clear' },
 });
 
-// Copied from emoji-mart for consistency with emoji picker and since
-// they don't export the icons in the package
-const icons = {
-  loupe: (
-    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'>
-      <path d='M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z' />
-    </svg>
-  ),
-
-  delete: (
-    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'>
-      <path d='M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z' />
-    </svg>
-  ),
-};
-
 const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
 
 class LanguageDropdownMenu extends React.PureComponent {
@@ -242,7 +227,7 @@ class LanguageDropdownMenu extends React.PureComponent {
           <div className={`language-dropdown__dropdown ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}>
             <div className='emoji-mart-search'>
               <input type='search' value={searchValue} onChange={this.handleSearchChange} onKeyDown={this.handleSearchKeyDown} placeholder={intl.formatMessage(messages.search)} autoFocus />
-              <button className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? icons.loupe : icons.delete}</button>
+              <button className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button>
             </div>
 
             <div className='language-dropdown__dropdown__results emoji-mart-scroll' role='listbox' ref={this.setListRef}>
diff --git a/app/javascript/mastodon/features/filters/added_to_filter.js b/app/javascript/mastodon/features/filters/added_to_filter.js
new file mode 100644
index 000000000..3785eb3c5
--- /dev/null
+++ b/app/javascript/mastodon/features/filters/added_to_filter.js
@@ -0,0 +1,102 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import { FormattedMessage } from 'react-intl';
+import { toServerSideType } from 'mastodon/utils/filters';
+import Button from 'mastodon/components/button';
+import { connect } from 'react-redux';
+
+const mapStateToProps = (state, { filterId }) => ({
+  filter: state.getIn(['filters', filterId]),
+});
+
+export default @connect(mapStateToProps)
+class AddedToFilter extends React.PureComponent {
+
+  static propTypes = {
+    onClose: PropTypes.func.isRequired,
+    contextType: PropTypes.string,
+    filter: ImmutablePropTypes.map.isRequired,
+    dispatch: PropTypes.func.isRequired,
+  };
+
+  handleCloseClick = () => {
+    const { onClose } = this.props;
+    onClose();
+  };
+
+  render () {
+    const { filter, contextType } = this.props;
+
+    let expiredMessage = null;
+    if (filter.get('expires_at') && filter.get('expires_at') < new Date()) {
+      expiredMessage = (
+        <React.Fragment>
+          <h4 className='report-dialog-modal__subtitle'><FormattedMessage id='filter_modal.added.expired_title' defaultMessage='Expired filter!' /></h4>
+          <p className='report-dialog-modal__lead'>
+            <FormattedMessage
+              id='filter_modal.added.expired_explanation'
+              defaultMessage='This filter category has expired, you will need to change the expiration date for it to apply.'
+            />
+          </p>
+        </React.Fragment>
+      );
+    }
+
+    let contextMismatchMessage = null;
+    if (contextType && !filter.get('context').includes(toServerSideType(contextType))) {
+      contextMismatchMessage = (
+        <React.Fragment>
+          <h4 className='report-dialog-modal__subtitle'><FormattedMessage id='filter_modal.added.context_mismatch_title' defaultMessage='Context mismatch!' /></h4>
+          <p className='report-dialog-modal__lead'>
+            <FormattedMessage
+              id='filter_modal.added.context_mismatch_explanation'
+              defaultMessage='This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.'
+            />
+          </p>
+        </React.Fragment>
+      );
+    }
+
+    const settings_link = (
+      <a href={`/filters/${filter.get('id')}/edit`}>
+        <FormattedMessage
+          id='filter_modal.added.settings_link'
+          defaultMessage='settings page'
+        />
+      </a>
+    );
+
+    return (
+      <React.Fragment>
+        <h3 className='report-dialog-modal__title'><FormattedMessage id='filter_modal.added.title' defaultMessage='Filter added!' /></h3>
+        <p className='report-dialog-modal__lead'>
+          <FormattedMessage
+            id='filter_modal.added.short_explanation'
+            defaultMessage='This post has been added to the following filter category: {title}.'
+            values={{ title: filter.get('title') }}
+          />
+        </p>
+
+        {expiredMessage}
+        {contextMismatchMessage}
+
+        <h4 className='report-dialog-modal__subtitle'><FormattedMessage id='filter_modal.added.review_and_configure_title' defaultMessage='Filter settings' /></h4>
+        <p className='report-dialog-modal__lead'>
+          <FormattedMessage
+            id='filter_modal.added.review_and_configure'
+            defaultMessage='To review and further configure this filter category, go to the {settings_link}.'
+            values={{ settings_link }}
+          />
+        </p>
+
+        <div className='flex-spacer' />
+
+        <div className='report-dialog-modal__actions'>
+          <Button onClick={this.handleCloseClick}><FormattedMessage id='report.close' defaultMessage='Done' /></Button>
+        </div>
+      </React.Fragment>
+    );
+  }
+
+}
diff --git a/app/javascript/mastodon/features/filters/select_filter.js b/app/javascript/mastodon/features/filters/select_filter.js
new file mode 100644
index 000000000..b5b354529
--- /dev/null
+++ b/app/javascript/mastodon/features/filters/select_filter.js
@@ -0,0 +1,192 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { toServerSideType } from 'mastodon/utils/filters';
+import { loupeIcon, deleteIcon } from 'mastodon/utils/icons';
+import Icon from 'mastodon/components/icon';
+import fuzzysort from 'fuzzysort';
+
+const messages = defineMessages({
+  search: { id: 'filter_modal.select_filter.search', defaultMessage: 'Search or create' },
+  clear: { id: 'emoji_button.clear', defaultMessage: 'Clear' },
+});
+
+const mapStateToProps = (state, { contextType }) => ({
+  filters: Array.from(state.get('filters').values()).map((filter) => [
+    filter.get('id'),
+    filter.get('title'),
+    filter.get('keywords')?.map((keyword) => keyword.get('keyword')).join('\n'),
+    filter.get('expires_at') && filter.get('expires_at') < new Date(),
+    contextType && !filter.get('context').includes(toServerSideType(contextType)),
+  ]),
+});
+
+export default @connect(mapStateToProps)
+@injectIntl
+class SelectFilter extends React.PureComponent {
+
+  static propTypes = {
+    onSelectFilter: PropTypes.func.isRequired,
+    onNewFilter: PropTypes.func.isRequired,
+    filters: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.object)),
+    intl: PropTypes.object.isRequired,
+  };
+
+  state = {
+    searchValue: '',
+  };
+
+  search () {
+    const { filters } = this.props;
+    const { searchValue } = this.state;
+
+    if (searchValue === '') {
+      return filters;
+    }
+
+    return fuzzysort.go(searchValue, filters, {
+      keys: ['1', '2'],
+      limit: 5,
+      threshold: -10000,
+    }).map(result => result.obj);
+  }
+
+  renderItem = filter => {
+    let warning = null;
+    if (filter[3] || filter[4]) {
+      warning = (
+        <span className='language-dropdown__dropdown__results__item__common-name'>
+          (
+          {filter[3] && <FormattedMessage id='filter_modal.select_filter.expired' defaultMessage='expired' />}
+          {filter[3] && filter[4] && ', '}
+          {filter[4] && <FormattedMessage id='filter_modal.select_filter.context_mismatch' defaultMessage='does not apply to this context' />}
+          )
+        </span>
+      );
+    }
+
+    return (
+      <div key={filter[0]} role='button' tabIndex='0' data-index={filter[0]} className='language-dropdown__dropdown__results__item' onClick={this.handleItemClick} onKeyDown={this.handleKeyDown}>
+        <span className='language-dropdown__dropdown__results__item__native-name'>{filter[1]}</span> {warning}
+      </div>
+    );
+  }
+
+  renderCreateNew (name) {
+    return (
+      <div key='add-new-filter' role='button' tabIndex='0' className='language-dropdown__dropdown__results__item' onClick={this.handleNewFilterClick} onKeyDown={this.handleKeyDown}>
+        <Icon id='plus' fixedWidth /> <FormattedMessage id='filter_modal.select_filter.prompt_new' defaultMessage='New category: {name}' values={{ name }} />
+      </div>
+    );
+  }
+
+  handleSearchChange = ({ target }) => {
+    this.setState({ searchValue: target.value });
+  }
+
+  setListRef = c => {
+    this.listNode = c;
+  }
+
+  handleKeyDown = e => {
+    const index = Array.from(this.listNode.childNodes).findIndex(node => node === e.currentTarget);
+
+    let element = null;
+
+    switch(e.key) {
+    case ' ':
+    case 'Enter':
+      e.currentTarget.click();
+      break;
+    case 'ArrowDown':
+      element = this.listNode.childNodes[index + 1] || this.listNode.firstChild;
+      break;
+    case 'ArrowUp':
+      element = this.listNode.childNodes[index - 1] || this.listNode.lastChild;
+      break;
+    case 'Tab':
+      if (e.shiftKey) {
+        element = this.listNode.childNodes[index - 1] || this.listNode.lastChild;
+      } else {
+        element = this.listNode.childNodes[index + 1] || this.listNode.firstChild;
+      }
+      break;
+    case 'Home':
+      element = this.listNode.firstChild;
+      break;
+    case 'End':
+      element = this.listNode.lastChild;
+      break;
+    }
+
+    if (element) {
+      element.focus();
+      e.preventDefault();
+      e.stopPropagation();
+    }
+  }
+
+  handleSearchKeyDown = e => {
+    let element = null;
+
+    switch(e.key) {
+    case 'Tab':
+    case 'ArrowDown':
+      element = this.listNode.firstChild;
+
+      if (element) {
+        element.focus();
+        e.preventDefault();
+        e.stopPropagation();
+      }
+
+      break;
+    }
+  }
+
+  handleClear = () => {
+    this.setState({ searchValue: '' });
+  }
+
+  handleItemClick = e => {
+    const value = e.currentTarget.getAttribute('data-index');
+
+    e.preventDefault();
+
+    this.props.onSelectFilter(value);
+  }
+
+  handleNewFilterClick = e => {
+    e.preventDefault();
+
+    this.props.onNewFilter(this.state.searchValue);
+  };
+
+  render () {
+    const { intl } = this.props;
+
+    const { searchValue } = this.state;
+    const isSearching = searchValue !== '';
+    const results = this.search();
+
+    return (
+      <React.Fragment>
+        <h3 className='report-dialog-modal__title'><FormattedMessage id='filter_modal.select_filter.title' defaultMessage='Filter this post' /></h3>
+        <p className='report-dialog-modal__lead'><FormattedMessage id='filter_modal.select_filter.subtitle' defaultMessage='Use an existing category or create a new one' /></p>
+
+        <div className='emoji-mart-search'>
+          <input type='search' value={searchValue} onChange={this.handleSearchChange} onKeyDown={this.handleSearchKeyDown} placeholder={intl.formatMessage(messages.search)} autoFocus />
+          <button className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button>
+        </div>
+
+        <div className='language-dropdown__dropdown__results emoji-mart-scroll' role='listbox' ref={this.setListRef}>
+          {results.map(this.renderItem)}
+          {isSearching && this.renderCreateNew(searchValue) }
+        </div>
+
+      </React.Fragment>
+    );
+  }
+
+}
diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js
index 13bce1b83..5c43c2038 100644
--- a/app/javascript/mastodon/features/status/components/detailed_status.js
+++ b/app/javascript/mastodon/features/status/components/detailed_status.js
@@ -138,7 +138,11 @@ class DetailedStatus extends ImmutablePureComponent {
             backgroundColor={attachment.getIn(['meta', 'colors', 'background'])}
             foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])}
             accentColor={attachment.getIn(['meta', 'colors', 'accent'])}
+            sensitive={status.get('sensitive')}
+            visible={this.props.showMedia}
+            blurhash={attachment.get('blurhash')}
             height={150}
+            onToggleVisibility={this.props.onToggleMediaVisibility}
           />
         );
       } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
diff --git a/app/javascript/mastodon/features/ui/components/filter_modal.js b/app/javascript/mastodon/features/ui/components/filter_modal.js
new file mode 100644
index 000000000..376db961d
--- /dev/null
+++ b/app/javascript/mastodon/features/ui/components/filter_modal.js
@@ -0,0 +1,134 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { fetchStatus } from 'mastodon/actions/statuses';
+import { fetchFilters, createFilter, createFilterStatus } from 'mastodon/actions/filters';
+import PropTypes from 'prop-types';
+import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import IconButton from 'mastodon/components/icon_button';
+import SelectFilter from 'mastodon/features/filters/select_filter';
+import AddedToFilter from 'mastodon/features/filters/added_to_filter';
+
+const messages = defineMessages({
+  close: { id: 'lightbox.close', defaultMessage: 'Close' },
+});
+
+export default @connect(undefined)
+@injectIntl
+class FilterModal extends ImmutablePureComponent {
+
+  static propTypes = {
+    statusId: PropTypes.string.isRequired,
+    contextType: PropTypes.string,
+    dispatch: PropTypes.func.isRequired,
+    intl: PropTypes.object.isRequired,
+  };
+
+  state = {
+    step: 'select',
+    filterId: null,
+    isSubmitting: false,
+    isSubmitted: false,
+  };
+
+  handleNewFilterSuccess = (result) => {
+    this.handleSelectFilter(result.id);
+  };
+
+  handleSuccess = () => {
+    const { dispatch, statusId } = this.props;
+    dispatch(fetchStatus(statusId, true));
+    this.setState({ isSubmitting: false, isSubmitted: true, step: 'submitted' });
+  };
+
+  handleFail = () => {
+    this.setState({ isSubmitting: false });
+  };
+
+  handleNextStep = step => {
+    this.setState({ step });
+  };
+
+  handleSelectFilter = (filterId) => {
+    const { dispatch, statusId } = this.props;
+
+    this.setState({ isSubmitting: true, filterId });
+
+    dispatch(createFilterStatus({
+      filter_id: filterId,
+      status_id: statusId,
+    }, this.handleSuccess, this.handleFail));
+  };
+
+  handleNewFilter = (title) => {
+    const { dispatch } = this.props;
+
+    this.setState({ isSubmitting: true });
+
+    dispatch(createFilter({
+      title,
+      context: ['home', 'notifications', 'public', 'thread', 'account'],
+      action: 'warn',
+    }, this.handleNewFilterSuccess, this.handleFail));
+  };
+
+  componentDidMount () {
+    const { dispatch } = this.props;
+
+    dispatch(fetchFilters());
+  }
+
+  render () {
+    const {
+      intl,
+      statusId,
+      contextType,
+      onClose,
+    } = this.props;
+
+    const {
+      step,
+      filterId,
+    } = this.state;
+
+    let stepComponent;
+
+    switch(step) {
+    case 'select':
+      stepComponent = (
+        <SelectFilter
+          contextType={contextType}
+          onSelectFilter={this.handleSelectFilter}
+          onNewFilter={this.handleNewFilter}
+        />
+      );
+      break;
+    case 'create':
+      stepComponent = null;
+      break;
+    case 'submitted':
+      stepComponent = (
+        <AddedToFilter
+          contextType={contextType}
+          filterId={filterId}
+          statusId={statusId}
+          onClose={onClose}
+        />
+      );
+    }
+
+    return (
+      <div className='modal-root__modal report-dialog-modal'>
+        <div className='report-modal__target'>
+          <IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={20} />
+          <FormattedMessage id='filter_modal.title.status' defaultMessage='Filter a post' />
+        </div>
+
+        <div className='report-dialog-modal__container'>
+          {stepComponent}
+        </div>
+      </div>
+    );
+  }
+
+}
diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js
index 3fc235849..b2c30e079 100644
--- a/app/javascript/mastodon/features/ui/components/modal_root.js
+++ b/app/javascript/mastodon/features/ui/components/modal_root.js
@@ -20,6 +20,7 @@ import {
   ListEditor,
   ListAdder,
   CompareHistoryModal,
+  FilterModal,
 } from 'mastodon/features/ui/util/async-components';
 
 const MODAL_COMPONENTS = {
@@ -37,6 +38,7 @@ const MODAL_COMPONENTS = {
   'FOCAL_POINT': () => Promise.resolve({ default: FocalPointModal }),
   'LIST_ADDER': ListAdder,
   'COMPARE_HISTORY': CompareHistoryModal,
+  'FILTER': FilterModal,
 };
 
 export default class ModalRoot extends React.PureComponent {
diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js
index 92c683e2f..29b06206a 100644
--- a/app/javascript/mastodon/features/ui/util/async-components.js
+++ b/app/javascript/mastodon/features/ui/util/async-components.js
@@ -161,3 +161,7 @@ export function CompareHistoryModal () {
 export function Explore () {
   return import(/* webpackChunkName: "features/explore" */'../../explore');
 }
+
+export function FilterModal () {
+  return import(/*webpackChunkName: "modals/filter_modal" */'../components/filter_modal');
+}
diff --git a/app/javascript/mastodon/locales/af.json b/app/javascript/mastodon/locales/af.json
index 942c8191f..86d590654 100644
--- a/app/javascript/mastodon/locales/af.json
+++ b/app/javascript/mastodon/locales/af.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Aankondiging",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index 13d6e4e7a..220aa14ee 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "المعذرة!",
   "announcement.announcement": "إعلان",
   "attachments_list.unprocessed": "(غير معالَج)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} في الأسبوع",
   "boost_modal.combo": "يُمكنك الضّغط على {combo} لتخطي هذا في المرة المُقبلة",
   "bundle_column_error.body": "لقد حدث خطأ ما أثناء تحميل هذا العنصر.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "الأخبار",
   "explore.trending_statuses": "المنشورات",
   "explore.trending_tags": "الوسوم",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "تم",
   "follow_recommendations.heading": "تابع الأشخاص الذين ترغب في رؤية منشوراتهم! إليك بعض الاقتراحات.",
   "follow_recommendations.lead": "ستظهر منشورات الأشخاص الذين تُتابعتهم بترتيب تسلسلي زمني على صفحتك الرئيسية. لا تخف إذا ارتكبت أي أخطاء، تستطيع إلغاء متابعة أي شخص في أي وقت تريد!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "عُدّل {count, plural, zero {} one {{count} مرة} two {{count} مرتين} few {{count} مرات} many {{count} مرات} other {{count} مرة}}",
   "status.embed": "إدماج",
   "status.favourite": "أضف إلى المفضلة",
+  "status.filter": "Filter this post",
   "status.filtered": "مُصفّى",
   "status.hide": "Hide toot",
   "status.history.created": "أنشأه {name} {date}",
diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json
index 034885e81..dba626299 100644
--- a/app/javascript/mastodon/locales/ast.json
+++ b/app/javascript/mastodon/locales/ast.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "¡Meca!",
   "announcement.announcement": "Anunciu",
   "attachments_list.unprocessed": "(ensin procesar)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} per selmana",
   "boost_modal.combo": "Pues primir {combo} pa saltar esto la próxima vegada",
   "bundle_column_error.body": "Asocedió daqué malo mentanto se cargaba esti componente.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Noticies",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Etiquetes",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Empotrar",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 89f2efc85..4ded919e0 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Опаа!",
   "announcement.announcement": "Оповестяване",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} на седмица",
   "boost_modal.combo": "Можете да натиснете {combo}, за да пропуснете това следващия път",
   "bundle_column_error.body": "Нещо се обърка при зареждането на този компонент.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Следвайте хора, които харесвате, за да виждате техните съобщения! Ето някои предложения.",
   "follow_recommendations.lead": "Съобщения от хора, които следвате, ще се показват в хронологичен ред на вашата главна страница. Не се страхувайте, че ще сгрешите, по всяко време много лесно можете да спрете да ги следвате!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Вграждане",
   "status.favourite": "Предпочитани",
+  "status.filter": "Filter this post",
   "status.filtered": "Филтрирано",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json
index 852c4c720..94b0477b5 100644
--- a/app/javascript/mastodon/locales/bn.json
+++ b/app/javascript/mastodon/locales/bn.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "ওহো!",
   "announcement.announcement": "ঘোষণা",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "প্রতি সপ্তাহে {count}",
   "boost_modal.combo": "পরেরবার আপনি {combo} টিপলে এটি আর আসবে না",
   "bundle_column_error.body": "এই অংশটি দেখতে যেয়ে কোনো সমস্যা হয়েছে।.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "সম্পন্ন",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "এমবেড করতে",
   "status.favourite": "পছন্দের করতে",
+  "status.filter": "Filter this post",
   "status.filtered": "ছাঁকনিদিত",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/br.json b/app/javascript/mastodon/locales/br.json
index ac504c49c..50837691f 100644
--- a/app/javascript/mastodon/locales/br.json
+++ b/app/javascript/mastodon/locales/br.json
@@ -18,7 +18,7 @@
   "account.followers": "Heulier·ezed·ien",
   "account.followers.empty": "Den na heul an implijer-mañ c'hoazh.",
   "account.followers_counter": "{count, plural, other{{counter} Heulier}}",
-  "account.following": "Following",
+  "account.following": "O heuliañ",
   "account.following_counter": "{count, plural, other {{counter} Heuliañ}}",
   "account.follows.empty": "An implijer·ez-mañ na heul den ebet.",
   "account.follows_you": "Ho heul",
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Hopala!",
   "announcement.announcement": "Kemenn",
   "attachments_list.unprocessed": "(ket meret)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} bep sizhun",
   "boost_modal.combo": "Ar wezh kentañ e c'halliot gwaskañ war {combo} evit tremen hebiou",
   "bundle_column_error.body": "Degouezhet ez eus bet ur fazi en ur gargañ an elfenn-mañ.",
@@ -108,7 +109,7 @@
   "compose_form.poll.switch_to_single": "Kemmañ ar sontadeg evit aotren un dibab hepken",
   "compose_form.publish": "Embann",
   "compose_form.publish_loud": "{publish} !",
-  "compose_form.save_changes": "Save changes",
+  "compose_form.save_changes": "Enrollañ ar cheñchamantoù",
   "compose_form.sensitive.hide": "Merkañ ar media evel kizidik",
   "compose_form.sensitive.marked": "Merket eo ar media evel kizidik",
   "compose_form.sensitive.unmarked": "N'eo ket merket ar media evel kizidik",
@@ -149,7 +150,7 @@
   "embed.instructions": "Enkorfit ar statud war ho lec'hienn en ur eilañ ar c'hod dindan.",
   "embed.preview": "Setu penaos e vo diskouezet:",
   "emoji_button.activity": "Obererezh",
-  "emoji_button.clear": "Clear",
+  "emoji_button.clear": "Diverkañ",
   "emoji_button.custom": "Kempennet",
   "emoji_button.flags": "Bannieloù",
   "emoji_button.food": "Boued hag Evaj",
@@ -169,7 +170,7 @@
   "empty_column.blocks": "N'eus ket bet berzet implijer·ez ganeoc'h c'hoazh.",
   "empty_column.bookmarked_statuses": "N'ho peus toud ebet enrollet en ho sinedoù c'hoazh. Pa vo ouzhpennet unan ganeoc'h e teuio war wel amañ.",
   "empty_column.community": "Goulo eo ar red-amzer lec'hel. Skrivit'ta un dra evit lakaat tan dezhi !",
-  "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
+  "empty_column.direct": "N'ho peus kemennad prevez ebet c'hoazh. Pa vo resevet pe kaset unan ganeoc'h e teuio war wel amañ.",
   "empty_column.domain_blocks": "N'eus domani kuzh ebet c'hoazh.",
   "empty_column.explore_statuses": "Nothing is trending right now. Check back later!",
   "empty_column.favourited_statuses": "N'ho peus toud muiañ-karet ebet c'hoazh. Pa vo lakaet unan ganeoc'h e vo diskouezet amañ.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Keleier",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Gerioù-klik",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Graet",
   "follow_recommendations.heading": "Heuliit tud e plijfe deoc'h lenn toudoù! Setu un tamm alioù.",
   "follow_recommendations.lead": "Toudoù eus tud heuliet ganeoc'h a zeuio war wel en un urzh amzeroniezhel war ho red degemer. N'ho peus ket aon ober fazioù, gallout a rit paouez heuliañ tud ken aes n'eus forzh pegoulz!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Unan e mesk anezho",
   "hashtag.column_settings.tag_mode.none": "Hini ebet anezho",
   "hashtag.column_settings.tag_toggle": "Endelc'her gerioù-alc'hwez ouzhpenn evit ar bannad-mañ",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Heuliañ ar ger-klik",
   "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Paouez heuliañ ar ger-klik",
   "home.column_settings.basic": "Diazez",
   "home.column_settings.show_reblogs": "Diskouez ar skignadennoù",
   "home.column_settings.show_replies": "Diskouez ar respontoù",
@@ -270,8 +287,8 @@
   "lightbox.expand": "Ledanaat boest hewel ar skeudenn",
   "lightbox.next": "Da-heul",
   "lightbox.previous": "A-raok",
-  "limited_account_hint.action": "Show profile anyway",
-  "limited_account_hint.title": "This profile has been hidden by the moderators of your server.",
+  "limited_account_hint.action": "Diskouez an aelad memes tra",
+  "limited_account_hint.title": "Kuzhet eo bet an aelad-mañ gant habaskerien·ezed ho servijer.",
   "lists.account.add": "Ouzhpennañ d'al listenn",
   "lists.account.remove": "Lemel kuit eus al listenn",
   "lists.delete": "Dilemel al listenn",
@@ -317,8 +334,8 @@
   "navigation_bar.preferences": "Gwellvezioù",
   "navigation_bar.public_timeline": "Red-amzer kevreet",
   "navigation_bar.security": "Diogelroez",
-  "notification.admin.report": "{name} reported {target}",
-  "notification.admin.sign_up": "{name} signed up",
+  "notification.admin.report": "Disklêriet eo bet {target} gant {name}",
+  "notification.admin.sign_up": "{name} en·he deus lakaet e·hec'h anv",
   "notification.favourite": "{name} en/he deus lakaet ho toud en e/he muiañ-karet",
   "notification.follow": "heuliañ a ra {name} ac'hanoc'h",
   "notification.follow_request": "{name} en/he deus goulennet da heuliañ ac'hanoc'h",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Enframmañ",
   "status.favourite": "Muiañ-karet",
+  "status.filter": "Filter this post",
   "status.filtered": "Silet",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index bc6029fe0..f67a0f3fc 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Vaja!",
   "announcement.announcement": "Anunci",
   "attachments_list.unprocessed": "(sense processar)",
+  "audio.hide": "Amaga l'àudio",
   "autosuggest_hashtag.per_week": "{count} per setmana",
   "boost_modal.combo": "Pots prémer {combo} per evitar-ho el pròxim cop",
   "bundle_column_error.body": "S'ha produït un error en carregar aquest component.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Notícies",
   "explore.trending_statuses": "Publicacions",
   "explore.trending_tags": "Etiquetes",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Fet",
   "follow_recommendations.heading": "Segueix a la gent de la que t'agradaria veure les seves publicacions! Aquí hi ha algunes recomanacions.",
   "follow_recommendations.lead": "Les publicacions del usuaris que segueixes es mostraran en ordre cronològic en la teva línia de temps Inici. No tinguis por en cometre errors, pots fàcilment deixar de seguir-los en qualsevol moment!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Qualsevol d’aquests",
   "hashtag.column_settings.tag_mode.none": "Cap d’aquests",
   "hashtag.column_settings.tag_toggle": "Inclou etiquetes addicionals per a aquesta columna",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Segueix etiqueta",
   "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Deixa de seguir etiqueta",
   "home.column_settings.basic": "Bàsic",
   "home.column_settings.show_reblogs": "Mostra els impulsos",
   "home.column_settings.show_replies": "Mostra les respostes",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Editat {count, plural, one {{count} vegada} other {{count} vegades}}",
   "status.embed": "Incrusta",
   "status.favourite": "Favorit",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrat",
   "status.hide": "Amaga publicació",
   "status.history.created": "{name} ha creat {date}",
diff --git a/app/javascript/mastodon/locales/ckb.json b/app/javascript/mastodon/locales/ckb.json
index 80c5089ae..19d9550d0 100644
--- a/app/javascript/mastodon/locales/ckb.json
+++ b/app/javascript/mastodon/locales/ckb.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "تەححح!",
   "announcement.announcement": "بانگەواز",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} هەرهەفتە",
   "boost_modal.combo": "دەتوانیت دەست بنێی بە سەر {combo} بۆ بازدان لە جاری داهاتوو",
   "bundle_column_error.body": "هەڵەیەک ڕوویدا لەکاتی بارکردنی ئەم پێکهاتەیە.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "هەواڵەکان",
   "explore.trending_statuses": "نووسراوەکان",
   "explore.trending_tags": "هاشتاگ",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "تەواو",
   "follow_recommendations.heading": "شوێن ئەو کەسانە بکەون کە دەتەوێت پۆستەکان ببینیت لە! لێرەدا چەند پێشنیارێک هەیە.",
   "follow_recommendations.lead": "بابەتەکانی ئەو کەسانەی کە بەدوایدا دەگەڕێیت بە فەرمانی کرۆنۆلۆجی لە خواردنەکانی ماڵەکەت دەردەکەون. مەترسە لە هەڵەکردن، دەتوانیت بە ئاسانی خەڵک هەڵبکەیت هەر کاتێک!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "دەستکاریکراوە {count, plural, one {{count} کات} other {{count} کات}}",
   "status.embed": "نیشتەجێ بکە",
   "status.favourite": "دڵخواز",
+  "status.filter": "Filter this post",
   "status.filtered": "پاڵاوتن",
   "status.hide": "Hide toot",
   "status.history.created": "{name} دروستکراوە لە{date}",
diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json
index 2dbc256ee..5ca3f4a4b 100644
--- a/app/javascript/mastodon/locales/co.json
+++ b/app/javascript/mastodon/locales/co.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Uups!",
   "announcement.announcement": "Annunziu",
   "attachments_list.unprocessed": "(micca trattata)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} per settimana",
   "boost_modal.combo": "Pudete appughjà nant'à {combo} per saltà quessa a prussima volta",
   "bundle_column_error.body": "C'hè statu un prublemu caricandu st'elementu.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Fatta",
   "follow_recommendations.heading": "Siguitate a ghjente da quelli vulete vede i missaghji! Eccu qualchì ricumandazione.",
   "follow_recommendations.lead": "I missaghji da a ghjente che voi siguitate figureranu in ordine crunulogicu nant'a vostra pagina d'accolta. Ùn timite micca di fà un sbagliu, pudete sempre disabbunavvi d'un contu à ogni mumentu!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Integrà",
   "status.favourite": "Aghjunghje à i favuriti",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtratu",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index 2f667eae6..ef1a13d8f 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Jejda!",
   "announcement.announcement": "Oznámení",
   "attachments_list.unprocessed": "(nezpracováno)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} za týden",
   "boost_modal.combo": "Příště můžete pro přeskočení stisknout {combo}",
   "bundle_column_error.body": "Při načítání této komponenty se něco pokazilo.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Zprávy",
   "explore.trending_statuses": "Příspěvky",
   "explore.trending_tags": "Hashtagy",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Hotovo",
   "follow_recommendations.heading": "Sledujte lidi, jejichž příspěvky chcete vidět! Tady jsou nějaké návrhy.",
   "follow_recommendations.lead": "Příspěvky od lidí, které sledujete, se budou objevovat v chronologickém pořadí ve vaší domovské ose. Nebojte se, že uděláte chybu, můžete lidi stejně snadno kdykoliv přestat sledovat!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Upraven {count, plural, one {{count}krát} few {{count}krát} many {{count}krát} other {{count}krát}}",
   "status.embed": "Vložit na web",
   "status.favourite": "Oblíbit",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrováno",
   "status.hide": "Skrýt příspěvek",
   "status.history.created": "Uživatel {name} vytvořil {date}",
diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json
index 228fd280f..cb1c90d69 100644
--- a/app/javascript/mastodon/locales/cy.json
+++ b/app/javascript/mastodon/locales/cy.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Wps!",
   "announcement.announcement": "Cyhoeddiad",
   "attachments_list.unprocessed": "(heb eu prosesu)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Newyddion",
   "explore.trending_statuses": "Postiadau",
   "explore.trending_tags": "Hashnodau",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Wedi gorffen",
   "follow_recommendations.heading": "Dilynwch y bobl yr hoffech chi weld eu postiadau! Dyma ambell i awgrymiad.",
   "follow_recommendations.lead": "Bydd postiadau gan bobl rydych chi'n eu dilyn yn ymddangos mewn trefn amser ar eich ffrwd cartref. Peidiwch â bod ofn gwneud camgymeriadau, gallwch chi ddad-ddilyn pobl yr un mor hawdd unrhyw bryd!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Golygwyd {count, plural, one {unwaith} two {dwywaith} other {{count} gwaith}}",
   "status.embed": "Plannu",
   "status.favourite": "Hoffi",
+  "status.filter": "Filter this post",
   "status.filtered": "Wedi'i hidlo",
   "status.hide": "Hide toot",
   "status.history.created": "{name} greuodd {date}",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index 0898b9081..8f015b50d 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ups!",
   "announcement.announcement": "Bekendtgørelse",
   "attachments_list.unprocessed": "(ubehandlet)",
+  "audio.hide": "Skjul lyd",
   "autosuggest_hashtag.per_week": "{count} pr. uge",
   "boost_modal.combo": "Du kan trykke på {combo} for at overspringe dette næste gang",
   "bundle_column_error.body": "Noget gik galt under indlæsningen af denne komponent.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Nyheder",
   "explore.trending_statuses": "Indlæg",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Udført",
   "follow_recommendations.heading": "Følg personer du gerne vil se indlæg fra! Her er nogle forslag.",
   "follow_recommendations.lead": "Indlæg, fra personer du følger, vil fremgå kronologisk ordnet i dit hjemmefeed. Vær ikke bange for at begå fejl, da du altid og meget nemt kan ændre dit valg!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Nogle af disse",
   "hashtag.column_settings.tag_mode.none": "Ingen af disse",
   "hashtag.column_settings.tag_toggle": "Inkludér ekstra tags for denne kolonne",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Følg hashtag",
   "hashtag.total_volume": "Samlet volumen {days, plural, one {den seneste dag} other {de seneste {days} dage}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Stop med at følge hashtag",
   "home.column_settings.basic": "Grundlæggende",
   "home.column_settings.show_reblogs": "Vis boosts",
   "home.column_settings.show_replies": "Vis svar",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Redigeret {count, plural, one {{count} gang} other {{count} gange}}",
   "status.embed": "Indlejr",
   "status.favourite": "Favorit",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtreret",
   "status.hide": "Skjul indlæg",
   "status.history.created": "{name} oprettet {date}",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index 200b85152..fae92a4b6 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Hoppla!",
   "announcement.announcement": "Ankündigung",
   "attachments_list.unprocessed": "(ausstehend)",
+  "audio.hide": "Audio stummschalten",
   "autosuggest_hashtag.per_week": "{count} pro Woche",
   "boost_modal.combo": "Drücke {combo}, um dieses Fenster zu überspringen",
   "bundle_column_error.body": "Etwas ist beim Laden schiefgelaufen.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Nachrichten",
   "explore.trending_statuses": "Beiträge",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Fertig",
   "follow_recommendations.heading": "Folge Leuten, von denen du Beiträge sehen möchtest! Hier sind einige Vorschläge.",
   "follow_recommendations.lead": "Beiträge von Personen, denen du folgst, werden in chronologischer Reihenfolge auf deiner Startseite angezeigt. Hab keine Angst, Fehler zu machen, du kannst den Leuten jederzeit wieder entfolgen!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Eins von diesen",
   "hashtag.column_settings.tag_mode.none": "Keins von diesen",
   "hashtag.column_settings.tag_toggle": "Zusätzliche Hashtags für diese Spalte einfügen",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Hashtag folgen",
   "hashtag.total_volume": "Gesamtes Aufkommen {days, plural, one {am letzten Tag} other {in den letzten {days} Tagen}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Hashtag entfolgen",
   "home.column_settings.basic": "Einfach",
   "home.column_settings.show_reblogs": "Geteilte Beiträge anzeigen",
   "home.column_settings.show_replies": "Antworten anzeigen",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "{count, plural, one {{count} mal} other {{count} mal}} bearbeitet",
   "status.embed": "Einbetten",
   "status.favourite": "Favorisieren",
+  "status.filter": "Filter this post",
   "status.filtered": "Gefiltert",
   "status.hide": "Tröt verbergen",
   "status.history.created": "{name} erstellte {date}",
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index 0c0c912ce..f397851a8 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -635,6 +635,10 @@
       {
         "defaultMessage": "Unblock @{name}",
         "id": "account.unblock"
+      },
+      {
+        "defaultMessage": "Filter this post",
+        "id": "status.filter"
       }
     ],
     "path": "app/javascript/mastodon/components/status_action_bar.json"
@@ -1078,6 +1082,18 @@
       {
         "defaultMessage": "Download file",
         "id": "video.download"
+      },
+      {
+        "defaultMessage": "Hide audio",
+        "id": "audio.hide"
+      },
+      {
+        "defaultMessage": "Sensitive content",
+        "id": "status.sensitive_warning"
+      },
+      {
+        "defaultMessage": "Media hidden",
+        "id": "status.media_hidden"
       }
     ],
     "path": "app/javascript/mastodon/features/audio/index.json"
@@ -1871,6 +1887,84 @@
   {
     "descriptors": [
       {
+        "defaultMessage": "Expired filter!",
+        "id": "filter_modal.added.expired_title"
+      },
+      {
+        "defaultMessage": "This filter category has expired, you will need to change the expiration date for it to apply.",
+        "id": "filter_modal.added.expired_explanation"
+      },
+      {
+        "defaultMessage": "Context mismatch!",
+        "id": "filter_modal.added.context_mismatch_title"
+      },
+      {
+        "defaultMessage": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+        "id": "filter_modal.added.context_mismatch_explanation"
+      },
+      {
+        "defaultMessage": "settings page",
+        "id": "filter_modal.added.settings_link"
+      },
+      {
+        "defaultMessage": "Filter added!",
+        "id": "filter_modal.added.title"
+      },
+      {
+        "defaultMessage": "This post has been added to the following filter category: {title}.",
+        "id": "filter_modal.added.short_explanation"
+      },
+      {
+        "defaultMessage": "Filter settings",
+        "id": "filter_modal.added.review_and_configure_title"
+      },
+      {
+        "defaultMessage": "To review and further configure this filter category, go to the {settings_link}.",
+        "id": "filter_modal.added.review_and_configure"
+      },
+      {
+        "defaultMessage": "Done",
+        "id": "report.close"
+      }
+    ],
+    "path": "app/javascript/mastodon/features/filters/added_to_filter.json"
+  },
+  {
+    "descriptors": [
+      {
+        "defaultMessage": "Search or create",
+        "id": "filter_modal.select_filter.search"
+      },
+      {
+        "defaultMessage": "Clear",
+        "id": "emoji_button.clear"
+      },
+      {
+        "defaultMessage": "expired",
+        "id": "filter_modal.select_filter.expired"
+      },
+      {
+        "defaultMessage": "does not apply to this context",
+        "id": "filter_modal.select_filter.context_mismatch"
+      },
+      {
+        "defaultMessage": "New category: {name}",
+        "id": "filter_modal.select_filter.prompt_new"
+      },
+      {
+        "defaultMessage": "Filter this post",
+        "id": "filter_modal.select_filter.title"
+      },
+      {
+        "defaultMessage": "Use an existing category or create a new one",
+        "id": "filter_modal.select_filter.subtitle"
+      }
+    ],
+    "path": "app/javascript/mastodon/features/filters/select_filter.json"
+  },
+  {
+    "descriptors": [
+      {
         "defaultMessage": "Follow",
         "id": "account.follow"
       },
@@ -3416,6 +3510,19 @@
         "id": "lightbox.close"
       },
       {
+        "defaultMessage": "Filter a post",
+        "id": "filter_modal.title.status"
+      }
+    ],
+    "path": "app/javascript/mastodon/features/ui/components/filter_modal.json"
+  },
+  {
+    "descriptors": [
+      {
+        "defaultMessage": "Close",
+        "id": "lightbox.close"
+      },
+      {
         "defaultMessage": "Apply",
         "id": "upload_modal.apply"
       },
diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json
index 3cfce1647..999f67c73 100644
--- a/app/javascript/mastodon/locales/el.json
+++ b/app/javascript/mastodon/locales/el.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Εεπ!",
   "announcement.announcement": "Ανακοίνωση",
   "attachments_list.unprocessed": "(μη επεξεργασμένο)",
+  "audio.hide": "Απόκρυψη αρχείου ήχου",
   "autosuggest_hashtag.per_week": "{count} ανα εβδομάδα",
   "boost_modal.combo": "Μπορείς να πατήσεις {combo} για να το προσπεράσεις αυτό την επόμενη φορά",
   "bundle_column_error.body": "Κάτι πήγε στραβά ενώ φορτωνόταν αυτό το στοιχείο.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Νέα",
   "explore.trending_statuses": "Αναρτήσεις",
   "explore.trending_tags": "Ετικέτες",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Ολοκληρώθηκε",
   "follow_recommendations.heading": "Ακολουθήστε άτομα από τα οποία θα θέλατε να βλέπετε δημοσιεύσεις! Ορίστε μερικές προτάσεις.",
   "follow_recommendations.lead": "Οι αναρτήσεις των ατόμων που ακολουθείτε θα εμφανίζονται με χρονολογική σειρά στη ροή σας. Μη φοβάστε να κάνετε λάθη, καθώς μπορείτε πολύ εύκολα να σταματήσετε να ακολουθείτε άλλα άτομα οποιαδήποτε στιγμή!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Οποιοδήποτε από αυτά",
   "hashtag.column_settings.tag_mode.none": "Κανένα από αυτά",
   "hashtag.column_settings.tag_toggle": "Προσθήκη επιπλέον ταμπελών για την κολώνα",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Παρακολούθηση ετικέτας",
   "hashtag.total_volume": "Συνολικός όγκος κατά την τελευταία {days, plural, one {ημέρα} other {{days} ημέρες}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Διακοπή παρακολούθησης ετικέτας",
   "home.column_settings.basic": "Βασικές ρυθμίσεις",
   "home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
   "home.column_settings.show_replies": "Εμφάνιση απαντήσεων",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Ενσωμάτωσε",
   "status.favourite": "Σημείωσε ως αγαπημένο",
+  "status.filter": "Filter this post",
   "status.filtered": "Φιλτραρισμένα",
   "status.hide": "Απόκρυψη toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json
index 535c5852a..2287dcda5 100644
--- a/app/javascript/mastodon/locales/en-GB.json
+++ b/app/javascript/mastodon/locales/en-GB.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 60279436d..6a186562f 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -200,6 +201,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -475,6 +492,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index 67872ff0a..082c53de7 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Aj!",
   "announcement.announcement": "Anonco",
   "attachments_list.unprocessed": "(neprilaborita)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} semajne",
   "boost_modal.combo": "Vi povas premi {combo} por preterpasi sekvafoje",
   "bundle_column_error.body": "Io misfunkciis en la ŝargado de ĉi tiu elemento.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Novaĵoj",
   "explore.trending_statuses": "Afiŝoj",
   "explore.trending_tags": "Kradvortoj",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Farita",
   "follow_recommendations.heading": "Sekvi la personojn kies mesaĝojn vi volas vidi! Jen iom da sugestoj.",
   "follow_recommendations.lead": "La mesaĝoj de personoj kiujn vi sekvas, aperos laŭ kronologia ordo en via hejma templinio. Ne timu erari, vi povas ĉesi sekvi facile iam ajn!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Iu ajn",
   "hashtag.column_settings.tag_mode.none": "Neniu",
   "hashtag.column_settings.tag_toggle": "Aldoni pliajn etikedojn por ĉi tiu kolumno",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Sekvi la kradvorton",
   "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Ne plu sekvi la kradvorton",
   "home.column_settings.basic": "Bazaj agordoj",
   "home.column_settings.show_reblogs": "Montri plusendojn",
   "home.column_settings.show_replies": "Montri respondojn",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Redactita {count, plural, one {{count} fojon} other {{count} fojojn}}",
   "status.embed": "Enkorpigi",
   "status.favourite": "Aldoni al viaj preferaĵoj",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrita",
   "status.hide": "Kaŝi la mesaĝon",
   "status.history.created": "{name} kreis {date}",
diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json
index 0eeb6e1ff..8e4b906a2 100644
--- a/app/javascript/mastodon/locales/es-AR.json
+++ b/app/javascript/mastodon/locales/es-AR.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "¡Epa!",
   "announcement.announcement": "Anuncio",
   "attachments_list.unprocessed": "[sin procesar]",
+  "audio.hide": "Ocultar audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Noticias",
   "explore.trending_statuses": "Mensajes",
   "explore.trending_tags": "Etiquetas",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Listo",
   "follow_recommendations.heading": "¡Seguí cuentas cuyos mensajes te gustaría ver! Acá tenés algunas sugerencias.",
   "follow_recommendations.lead": "Los mensajes de las cuentas que seguís aparecerán en orden cronológico en la columna \"Inicio\". No tengás miedo de meter la pata, ¡podés dejar de seguir cuentas fácilmente en cualquier momento!",
@@ -220,9 +237,9 @@
   "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",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Seguir etiqueta",
   "hashtag.total_volume": "Volumen total en el/los último/s {days, plural, one {día} other {{days} días}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Dejar de seguir etiqueta",
   "home.column_settings.basic": "Básico",
   "home.column_settings.show_reblogs": "Mostrar adhesiones",
   "home.column_settings.show_replies": "Mostrar respuestas",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} veces}}",
   "status.embed": "Insertar",
   "status.favourite": "Marcar como favorito",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrado",
   "status.hide": "Ocultar mensaje",
   "status.history.created": "Creado por {name} el {date}",
diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json
index 23a8d7247..96f0a59dc 100644
--- a/app/javascript/mastodon/locales/es-MX.json
+++ b/app/javascript/mastodon/locales/es-MX.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "¡Ups!",
   "announcement.announcement": "Anuncio",
   "attachments_list.unprocessed": "(sin procesar)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Noticias",
   "explore.trending_statuses": "Publicaciones",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Hecho",
   "follow_recommendations.heading": "¡Sigue a gente que publique cosas que te gusten! Aquí tienes algunas sugerencias.",
   "follow_recommendations.lead": "Las publicaciones de la gente a la que sigas aparecerán ordenadas cronológicamente en Inicio. No tengas miedo de cometer errores, ¡puedes dejarles de seguir en cualquier momento con la misma facilidad!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Cualquiera de estos",
   "hashtag.column_settings.tag_mode.none": "Ninguno de estos",
   "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
-  "hashtag.follow": "Follow hashtag",
-  "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.follow": "Seguir etiqueta",
+  "hashtag.total_volume": "Volumen total en los últimos {days, plural, one {día} other {{days} días}}",
+  "hashtag.unfollow": "Dejar de seguir etiqueta",
   "home.column_settings.basic": "Básico",
   "home.column_settings.show_reblogs": "Mostrar retoots",
   "home.column_settings.show_replies": "Mostrar respuestas",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Editado {count, plural, one {{count} time} other {{count} veces}}",
   "status.embed": "Incrustado",
   "status.favourite": "Favorito",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrado",
   "status.hide": "Ocultar publicación",
   "status.history.created": "{name} creó {date}",
@@ -520,7 +538,7 @@
   "timeline_hint.resources.followers": "Seguidores",
   "timeline_hint.resources.follows": "Seguidos",
   "timeline_hint.resources.statuses": "Toots más antiguos",
-  "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
+  "trends.counter_by_accounts": "{count, plural, one {{counter} persona} other {{counter} personas}} en los últimos {days, plural, one {días} other {{days} días}}",
   "trends.trending_now": "Tendencia ahora",
   "ui.beforeunload": "Tu borrador se perderá si sales de Mastodon.",
   "units.short.billion": "{count} MM",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 857f3a3cd..57259e21c 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "¡Ups!",
   "announcement.announcement": "Anuncio",
   "attachments_list.unprocessed": "(sin procesar)",
+  "audio.hide": "Ocultar audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Noticias",
   "explore.trending_statuses": "Publicaciones",
   "explore.trending_tags": "Etiquetas",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Hecho",
   "follow_recommendations.heading": "¡Sigue a gente que publique cosas que te gusten! Aquí tienes algunas sugerencias.",
   "follow_recommendations.lead": "Las publicaciones de la gente a la que sigas aparecerán ordenadas cronológicamente en Inicio. No tengas miedo de cometer errores, ¡puedes dejarles de seguir en cualquier momento con la misma facilidad!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Cualquiera de estos",
   "hashtag.column_settings.tag_mode.none": "Ninguno de estos",
   "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Seguir etiqueta",
   "hashtag.total_volume": "Volumen total en los últimos {days, plural, one {día} other {{days} días}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Dejar de seguir etiqueta",
   "home.column_settings.basic": "Básico",
   "home.column_settings.show_reblogs": "Mostrar retoots",
   "home.column_settings.show_replies": "Mostrar respuestas",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} veces}}",
   "status.embed": "Incrustado",
   "status.favourite": "Favorito",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrado",
   "status.hide": "Ocultar publicación",
   "status.history.created": "{name} creó {date}",
diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json
index 2b6594b87..6737111fd 100644
--- a/app/javascript/mastodon/locales/et.json
+++ b/app/javascript/mastodon/locales/et.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oih!",
   "announcement.announcement": "Teadaanne",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} nädalas",
   "boost_modal.combo": "Võite vajutada {combo}, et see järgmine kord vahele jätta",
   "bundle_column_error.body": "Midagi läks valesti selle komponendi laadimisel.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Uudised",
   "explore.trending_statuses": "Postitused",
   "explore.trending_tags": "Sildid",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Sängita",
   "status.favourite": "Lemmik",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtreeritud",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index 44ab5f80e..c8062f004 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ene!",
   "announcement.announcement": "Iragarpena",
   "attachments_list.unprocessed": "(prozesatu gabe)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} asteko",
   "boost_modal.combo": "{combo} sakatu dezakezu hurrengoan hau saltatzeko",
   "bundle_column_error.body": "Zerbait okerra gertatu da osagai hau kargatzean.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Berriak",
   "explore.trending_statuses": "Bidalketak",
   "explore.trending_tags": "Traolak",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Egina",
   "follow_recommendations.heading": "Jarraitu jendea beren bidalketak ikusteko! Hemen dituzu iradokizun batzuk.",
   "follow_recommendations.lead": "Jarraitzen duzun jendearen bidalketak ordena kronologikoan agertuko dira zure hasierako jarioan. Ez izan akatsak egiteko beldurrik, jendea jarraitzeari uztea erraza da!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "{count, plural, one {behin} other {{count} aldiz}} editatua",
   "status.embed": "Txertatu",
   "status.favourite": "Gogokoa",
+  "status.filter": "Filter this post",
   "status.filtered": "Iragazita",
   "status.hide": "Hide toot",
   "status.history.created": "{name} erabiltzaileak sortua {date}",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index 977b0aa74..775f38475 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "ای وای!",
   "announcement.announcement": "اعلامیه",
   "attachments_list.unprocessed": "(پردازش نشده)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} در هفته",
   "boost_modal.combo": "دکمهٔ {combo} را بزنید تا دیگر این را نبینید",
   "bundle_column_error.body": "هنگام بار کردن این مولفه، اشتباهی رخ داد.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "اخبار",
   "explore.trending_statuses": "فرسته‌ها",
   "explore.trending_tags": "هشتگ‌ها",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "انجام شد",
   "follow_recommendations.heading": "افرادی را که می‌خواهید فرسته‌هایشان را ببینید پی‌گیری کنید! این‌ها تعدادی پیشنهاد هستند.",
   "follow_recommendations.lead": "فرسته‌های افرادی که دنبال می‌کنید به ترتیب زمانی در خوراک خانه‌تان نشان داده خواهد شد. از اشتباه کردن نترسید. می‌توانید به همین سادگی در هر زمانی از دنبال کردن افراد دست بکشید!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "{count, plural, one {{count} مرتبه} other {{count} مرتبه}} ویرایش شد",
   "status.embed": "جاسازی",
   "status.favourite": "پسندیدن",
+  "status.filter": "Filter this post",
   "status.filtered": "پالوده",
   "status.hide": "Hide toot",
   "status.history.created": "توسط {name} در {date} ایجاد شد",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 68dbe44aa..3eb0f3e06 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -18,7 +18,7 @@
   "account.followers": "Seuraajat",
   "account.followers.empty": "Kukaan ei seuraa tätä käyttäjää vielä.",
   "account.followers_counter": "{count, plural, one {{counter} seuraaja} other {{counter} seuraajat}}",
-  "account.following": "Following",
+  "account.following": "Seurataan",
   "account.following_counter": "{count, plural, one {{counter} seuraa} other {{counter} seuraa}}",
   "account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.",
   "account.follows_you": "Seuraa sinua",
@@ -41,12 +41,12 @@
   "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}",
   "account.unblock": "Salli @{name}",
   "account.unblock_domain": "Salli {domain}",
-  "account.unblock_short": "Unblock",
+  "account.unblock_short": "Poista esto",
   "account.unendorse": "Poista suosittelu profiilistasi",
   "account.unfollow": "Lopeta seuraaminen",
   "account.unmute": "Poista käyttäjän @{name} mykistys",
   "account.unmute_notifications": "Poista mykistys käyttäjän @{name} ilmoituksilta",
-  "account.unmute_short": "Unmute",
+  "account.unmute_short": "Poista mykistys",
   "account_note.placeholder": "Lisää muistiinpano napsauttamalla",
   "admin.dashboard.daily_retention": "Käyttäjän säilyminen rekisteröitymisen jälkeiseen päivään mennessä",
   "admin.dashboard.monthly_retention": "Käyttäjän säilyminen rekisteröitymisen jälkeiseen kuukauteen mennessä",
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Hups!",
   "announcement.announcement": "Ilmoitus",
   "attachments_list.unprocessed": "(käsittelemätön)",
+  "audio.hide": "Piilota ääni",
   "autosuggest_hashtag.per_week": "{count} viikossa",
   "boost_modal.combo": "Ensi kerralla voit ohittaa tämän painamalla {combo}",
   "bundle_column_error.body": "Jokin meni vikaan komponenttia ladattaessa.",
@@ -70,7 +71,7 @@
   "column.blocks": "Estetyt käyttäjät",
   "column.bookmarks": "Kirjanmerkit",
   "column.community": "Paikallinen aikajana",
-  "column.direct": "Direct messages",
+  "column.direct": "Yksityisviestit",
   "column.directory": "Selaa profiileja",
   "column.domain_blocks": "Piilotetut verkkotunnukset",
   "column.favourites": "Suosikit",
@@ -92,10 +93,10 @@
   "community.column_settings.local_only": "Vain paikalliset",
   "community.column_settings.media_only": "Vain media",
   "community.column_settings.remote_only": "Vain etäkäyttö",
-  "compose.language.change": "Change language",
-  "compose.language.search": "Search languages...",
+  "compose.language.change": "Vaihda kieli",
+  "compose.language.search": "Hae kieliä...",
   "compose_form.direct_message_warning_learn_more": "Lisätietoja",
-  "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.",
+  "compose_form.encryption_warning": "Mastodonin viestit eivät ole päästä päähän salattuja. Älä jaa arkaluonteisia tietoja Mastodonissa.",
   "compose_form.hashtag_warning": "Tätä julkaisua listata minkään hastagin alle, koska se on listaamaton. Ainoastaan julkisia julkaisuja etsiä hastageilla.",
   "compose_form.lock_disclaimer": "Tilisi ei ole {locked}. Kuka tahansa voi seurata tiliäsi ja nähdä vain seuraajille rajaamasi julkaisut.",
   "compose_form.lock_disclaimer.lock": "lukittu",
@@ -106,7 +107,7 @@
   "compose_form.poll.remove_option": "Poista tämä valinta",
   "compose_form.poll.switch_to_multiple": "Muuta kysely monivalinnaksi",
   "compose_form.poll.switch_to_single": "Muuta kysely sallimaan vain yksi valinta",
-  "compose_form.publish": "Publish",
+  "compose_form.publish": "Julkaise",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.save_changes": "Tallenna muutokset",
   "compose_form.sensitive.hide": "{count, plural, one {Merkitse media arkaluontoiseksi} other {Merkitse media arkaluontoiseksi}}",
@@ -149,7 +150,7 @@
   "embed.instructions": "Upota julkaisu verkkosivullesi kopioimalla alla oleva koodi.",
   "embed.preview": "Se tulee näyttämään tältä:",
   "emoji_button.activity": "Aktiviteetit",
-  "emoji_button.clear": "Clear",
+  "emoji_button.clear": "Tyhjennä",
   "emoji_button.custom": "Mukautetut",
   "emoji_button.flags": "Liput",
   "emoji_button.food": "Ruoka ja juoma",
@@ -169,7 +170,7 @@
   "empty_column.blocks": "Et ole vielä estänyt yhtään käyttäjää.",
   "empty_column.bookmarked_statuses": "Et ole vielä lisännyt viestejä kirjanmerkkeihisi. Kun lisäät yhden, se näkyy tässä.",
   "empty_column.community": "Paikallinen aikajana on tyhjä. Kirjoita jotain julkista, niin homma lähtee käyntiin!",
-  "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
+  "empty_column.direct": "Sinulla ei ole vielä yksityisviestejä. Kun lähetät tai vastaanotat sellaisen, se näkyy tässä.",
   "empty_column.domain_blocks": "Yhtään verkko-osoitetta ei ole vielä estetty.",
   "empty_column.explore_statuses": "Mikään ei ole nyt trendi. Tarkista myöhemmin!",
   "empty_column.favourited_statuses": "Et ole vielä lisännyt viestejä kirjanmerkkeihisi. Kun lisäät yhden, se näkyy tässä.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Uutiset",
   "explore.trending_statuses": "Viestit",
   "explore.trending_tags": "Aihetunnisteet",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Valmis",
   "follow_recommendations.heading": "Seuraa ihmisiä, joilta haluaisit nähdä julkaisuja! Tässä on muutamia ehdotuksia.",
   "follow_recommendations.lead": "Seuraamiesi julkaisut näkyvät aikajärjestyksessä kotisyötteessä. Älä pelkää seurata vahingossa, voit lopettaa seuraamisen yhtä helposti!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Mikä tahansa näistä",
   "hashtag.column_settings.tag_mode.none": "Ei mitään näistä",
   "hashtag.column_settings.tag_toggle": "Sisällytä lisätunnisteet tähän sarakkeeseen",
-  "hashtag.follow": "Follow hashtag",
-  "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.follow": "Seuraa hashtagia",
+  "hashtag.total_volume": "Kokonaismäärä viimeiset {days, plural, one {päivä} other {{days} päivää}}",
+  "hashtag.unfollow": "Lopeta seuraaminen hashtagilla",
   "home.column_settings.basic": "Perusasetukset",
   "home.column_settings.show_reblogs": "Näytä buustaukset",
   "home.column_settings.show_replies": "Näytä vastaukset",
@@ -237,7 +254,7 @@
   "keyboard_shortcuts.column": "Kohdista sarakkeeseen",
   "keyboard_shortcuts.compose": "siirry tekstinsyöttöön",
   "keyboard_shortcuts.description": "Kuvaus",
-  "keyboard_shortcuts.direct": "to open direct messages column",
+  "keyboard_shortcuts.direct": "avaa yksityisviesti sarake",
   "keyboard_shortcuts.down": "Siirry listassa alaspäin",
   "keyboard_shortcuts.enter": "Avaa julkaisu",
   "keyboard_shortcuts.favourite": "Lisää suosikkeihin",
@@ -270,8 +287,8 @@
   "lightbox.expand": "Laajenna kuvan näkymälaatikko",
   "lightbox.next": "Seuraava",
   "lightbox.previous": "Edellinen",
-  "limited_account_hint.action": "Show profile anyway",
-  "limited_account_hint.title": "This profile has been hidden by the moderators of your server.",
+  "limited_account_hint.action": "Näytä profiili joka tapauksessa",
+  "limited_account_hint.title": "Tämä profiili on piilotettu serverisi valvojien toimesta.",
   "lists.account.add": "Lisää listaan",
   "lists.account.remove": "Poista listasta",
   "lists.delete": "Poista lista",
@@ -298,11 +315,11 @@
   "navigation_bar.bookmarks": "Kirjanmerkit",
   "navigation_bar.community_timeline": "Paikallinen aikajana",
   "navigation_bar.compose": "Luo uusi viesti",
-  "navigation_bar.direct": "Direct messages",
+  "navigation_bar.direct": "Yksityisviestit",
   "navigation_bar.discover": "Löydä uutta",
   "navigation_bar.domain_blocks": "Estetyt verkkotunnukset",
   "navigation_bar.edit_profile": "Muokkaa profiilia",
-  "navigation_bar.explore": "Explore",
+  "navigation_bar.explore": "Selaa",
   "navigation_bar.favourites": "Suosikit",
   "navigation_bar.filters": "Mykistetyt sanat",
   "navigation_bar.follow_requests": "Seuraamispyynnöt",
@@ -317,7 +334,7 @@
   "navigation_bar.preferences": "Asetukset",
   "navigation_bar.public_timeline": "Yleinen aikajana",
   "navigation_bar.security": "Turvallisuus",
-  "notification.admin.report": "{name} reported {target}",
+  "notification.admin.report": "{name} ilmoitti {target}",
   "notification.admin.sign_up": "{name} rekisteröitynyt",
   "notification.favourite": "{name} tykkäsi viestistäsi",
   "notification.follow": "{name} seurasi sinua",
@@ -330,7 +347,7 @@
   "notification.update": "{name} muokkasi viestiä",
   "notifications.clear": "Tyhjennä ilmoitukset",
   "notifications.clear_confirmation": "Haluatko varmasti poistaa kaikki ilmoitukset pysyvästi?",
-  "notifications.column_settings.admin.report": "New reports:",
+  "notifications.column_settings.admin.report": "Uudet raportit:",
   "notifications.column_settings.admin.sign_up": "Uudet kirjautumiset:",
   "notifications.column_settings.alert": "Työpöytäilmoitukset",
   "notifications.column_settings.favourite": "Tykkäykset:",
@@ -377,12 +394,12 @@
   "poll_button.remove_poll": "Poista kysely",
   "privacy.change": "Muuta julkaisun näkyvyyttä",
   "privacy.direct.long": "Julkaise vain mainituille käyttäjille",
-  "privacy.direct.short": "Direct",
+  "privacy.direct.short": "Vain mainitut henkilöt",
   "privacy.private.long": "Julkaise vain seuraajille",
-  "privacy.private.short": "Followers-only",
-  "privacy.public.long": "Visible for all",
+  "privacy.private.short": "Vain seuraajat",
+  "privacy.public.long": "Näkyvissä kaikille",
   "privacy.public.short": "Julkinen",
-  "privacy.unlisted.long": "Visible for all, but opted-out of discovery features",
+  "privacy.unlisted.long": "Näkyvissä kaikille, mutta jättäen pois hakemisen mahdollisuus",
   "privacy.unlisted.short": "Listaamaton julkinen",
   "refresh": "Päivitä",
   "regeneration_indicator.label": "Ladataan…",
@@ -436,11 +453,11 @@
   "report.thanks.title_actionable": "Kiitos raportista, tutkimme asiaa.",
   "report.unfollow": "Lopeta seuraaminen @{name}",
   "report.unfollow_explanation": "Seuraat tätä tiliä. Jotta et enää näkisi heidän kirjoituksiaan, lopeta niiden seuraaminen.",
-  "report_notification.attached_statuses": "{count, plural, one {{count} post} other {{count} posts}} attached",
-  "report_notification.categories.other": "Other",
-  "report_notification.categories.spam": "Spam",
-  "report_notification.categories.violation": "Rule violation",
-  "report_notification.open": "Open report",
+  "report_notification.attached_statuses": "{count, plural, one {{count} post} other {{count} viestiä}} liitteenä",
+  "report_notification.categories.other": "Muu",
+  "report_notification.categories.spam": "Roskaposti",
+  "report_notification.categories.violation": "Sääntöjen rikkominen",
+  "report_notification.open": "Avaa raportti",
   "search.placeholder": "Hae",
   "search_popout.search_format": "Tarkennettu haku",
   "search_popout.tips.full_text": "Tekstihaku listaa tilapäivitykset, jotka olet kirjoittanut, lisännyt suosikkeihisi, boostannut tai joissa sinut mainitaan, sekä tekstin sisältävät käyttäjänimet, nimimerkit ja hastagit.",
@@ -470,8 +487,9 @@
   "status.edited_x_times": "Muokattu {count, plural, one {{count} aika} other {{count} kertaa}}",
   "status.embed": "Upota",
   "status.favourite": "Tykkää",
+  "status.filter": "Filter this post",
   "status.filtered": "Suodatettu",
-  "status.hide": "Hide toot",
+  "status.hide": "Piilota toot",
   "status.history.created": "{name} luotu {date}",
   "status.history.edited": "{name} muokkasi {date}",
   "status.load_more": "Lataa lisää",
@@ -495,7 +513,7 @@
   "status.report": "Raportoi @{name}",
   "status.sensitive_warning": "Arkaluontoista sisältöä",
   "status.share": "Jaa",
-  "status.show_filter_reason": "Show anyway",
+  "status.show_filter_reason": "Näytä joka tapauksessa",
   "status.show_less": "Näytä vähemmän",
   "status.show_less_all": "Näytä vähemmän kaikista",
   "status.show_more": "Näytä lisää",
@@ -520,7 +538,7 @@
   "timeline_hint.resources.followers": "Seuraajat",
   "timeline_hint.resources.follows": "Seuraa",
   "timeline_hint.resources.statuses": "Vanhemmat julkaisut",
-  "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
+  "trends.counter_by_accounts": "{count, plural, one {{counter} henkilö} other {{counter} henkilöä}} viimeinen {days, plural, one {päivä} other {{days} päivää}}",
   "trends.trending_now": "Suosittua nyt",
   "ui.beforeunload": "Luonnos häviää, jos poistut Mastodonista.",
   "units.short.billion": "{count} mrd.",
@@ -532,7 +550,7 @@
   "upload_error.poll": "Tiedon lataaminen ei ole sallittua kyselyissä.",
   "upload_form.audio_description": "Kuvaile kuulovammaisille",
   "upload_form.description": "Anna kuvaus näkörajoitteisia varten",
-  "upload_form.description_missing": "No description added",
+  "upload_form.description_missing": "Kuvausta ei ole lisätty",
   "upload_form.edit": "Kuvaile",
   "upload_form.thumbnail": "Vaihda pikkukuva",
   "upload_form.undo": "Peru",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index 93d68190e..cc710250d 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oups !",
   "announcement.announcement": "Annonce",
   "attachments_list.unprocessed": "(non traité)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} par semaine",
   "boost_modal.combo": "Vous pouvez appuyer sur {combo} pour passer ceci la prochaine fois",
   "bundle_column_error.body": "Une erreur s’est produite lors du chargement de ce composant.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Actualité",
   "explore.trending_statuses": "Messages",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Terminé",
   "follow_recommendations.heading": "Suivez les personnes dont vous aimeriez voir les messages ! Voici quelques suggestions.",
   "follow_recommendations.lead": "Les messages des personnes que vous suivez apparaîtront par ordre chronologique sur votre fil d'accueil. Ne craignez pas de faire des erreurs, vous pouvez arrêter de suivre les gens aussi facilement à tout moment !",
@@ -220,9 +237,9 @@
   "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 hashtags additionnels pour cette colonne",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Suivre le hashtag",
   "hashtag.total_volume": "Volume total {days, plural, one {des dernières 24h} other {des {days} derniers jours}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Ne plus suivre le hashtag",
   "home.column_settings.basic": "Basique",
   "home.column_settings.show_reblogs": "Afficher les partages",
   "home.column_settings.show_replies": "Afficher les réponses",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edité {count, plural, one {{count} fois} other {{count} fois}}",
   "status.embed": "Intégrer",
   "status.favourite": "Ajouter aux favoris",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtré",
   "status.hide": "Cacher le pouet",
   "status.history.created": "créé par {name} {date}",
diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json
index ea5a61cdc..a53a1cf52 100644
--- a/app/javascript/mastodon/locales/fy.json
+++ b/app/javascript/mastodon/locales/fy.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(net ferwurke)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Nijs",
   "explore.trending_statuses": "Berjochten",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Klear",
   "follow_recommendations.heading": "Folgje minsken wer as jo graach berjochten fan sjen wolle! Hjir binne wat suggestjes.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "{count, plural, one {{count} kear} other {{count} kearen}} bewurke",
   "status.embed": "Ynslute",
   "status.favourite": "Favorite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtere",
   "status.hide": "Hide toot",
   "status.history.created": "{name} makke dit {date}",
diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json
index 1dd7e635f..e05c4a41d 100644
--- a/app/javascript/mastodon/locales/ga.json
+++ b/app/javascript/mastodon/locales/ga.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Hiúps!",
   "announcement.announcement": "Fógra",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} per week",
   "boost_modal.combo": "Is féidir leat brúigh {combo} chun é seo a scipeáil an chéad uair eile",
   "bundle_column_error.body": "Something went wrong while loading this component.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Nuacht",
   "explore.trending_statuses": "Postálacha",
   "explore.trending_tags": "Haischlibeanna",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Déanta",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Curtha in eagar {count, plural, one {{count} uair amháin} two {{count} uair} few {{count} uair} many {{count} uair} other {{count} uair}}",
   "status.embed": "Embed",
   "status.favourite": "Rogha",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json
index f7ffe0d87..c58729271 100644
--- a/app/javascript/mastodon/locales/gd.json
+++ b/app/javascript/mastodon/locales/gd.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oich!",
   "announcement.announcement": "Brath-fios",
   "attachments_list.unprocessed": "(gun phròiseasadh)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} san t-seachdain",
   "boost_modal.combo": "Brùth air {combo} nam b’ fheàrr leat leum a ghearradh thar seo an ath-thuras",
   "bundle_column_error.body": "Chaidh rudeigin cearr nuair a dh’fheuch sinn ris a’ cho-phàirt seo a luchdadh.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Naidheachdan",
   "explore.trending_statuses": "Postaichean",
   "explore.trending_tags": "Tagaichean hais",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Deiseil",
   "follow_recommendations.heading": "Lean air daoine ma tha thu airson nam postaichean aca fhaicinn! Seo moladh no dà dhut.",
   "follow_recommendations.lead": "Nochdaidh na postaichean aig na daoine air a leanas tu a-rèir an ama air inbhir na dachaighe agad. Bi dàna on as urrainn dhut sgur de leantainn air daoine cuideachd uair sam bith!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Gin sam bith dhiubh",
   "hashtag.column_settings.tag_mode.none": "Às aonais gin sam bith dhiubh",
   "hashtag.column_settings.tag_toggle": "Gabh a-steach barrachd tagaichean sa cholbh seo",
-  "hashtag.follow": "Follow hashtag",
-  "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.follow": "Lean air an taga hais",
+  "hashtag.total_volume": "An t-iomlan sna {days, plural, one {{days} latha} two {{days} latha} few {{days} làithean} other {{days} latha}} seo chaidh",
+  "hashtag.unfollow": "Na lean air an taga hais tuilleadh",
   "home.column_settings.basic": "Bunasach",
   "home.column_settings.show_reblogs": "Seall na brosnachaidhean",
   "home.column_settings.show_replies": "Seall na freagairtean",
@@ -317,7 +334,7 @@
   "navigation_bar.preferences": "Roghainnean",
   "navigation_bar.public_timeline": "Loidhne-ama cho-naisgte",
   "navigation_bar.security": "Tèarainteachd",
-  "notification.admin.report": "{name} reported {target}",
+  "notification.admin.report": "Rinn {name} mu {target}",
   "notification.admin.sign_up": "Chlàraich {name}",
   "notification.favourite": "Is annsa le {name} am post agad",
   "notification.follow": "Tha {name} a’ leantainn ort a-nis",
@@ -330,7 +347,7 @@
   "notification.update": "Dheasaich {name} post",
   "notifications.clear": "Falamhaich na brathan",
   "notifications.clear_confirmation": "A bheil thu cinnteach gu bheil thu airson na brathan uile agad fhalamhachadh gu buan?",
-  "notifications.column_settings.admin.report": "New reports:",
+  "notifications.column_settings.admin.report": "Gearanan ùra:",
   "notifications.column_settings.admin.sign_up": "Clàraidhean ùra:",
   "notifications.column_settings.alert": "Brathan deasga",
   "notifications.column_settings.favourite": "Na h-annsachdan:",
@@ -388,11 +405,11 @@
   "regeneration_indicator.label": "’Ga luchdadh…",
   "regeneration_indicator.sublabel": "Tha inbhir na dachaigh agad ’ga ullachadh!",
   "relative_time.days": "{number}l",
-  "relative_time.full.days": "{count, plural, one {# latha} two {# latha} few {# làithean} other {# latha}} air ais",
-  "relative_time.full.hours": "{count, plural, one {# uair a thìde} two {# uair a thìde} few {# uairean a thìde} other {# uair a thìde}} air ais",
+  "relative_time.full.days": "{number, plural, one {# latha} two {# latha} few {# làithean} other {# latha}} air ais",
+  "relative_time.full.hours": "{number, plural, one {# uair a thìde} two {# uair a thìde} few {# uairean a thìde} other {# uair a thìde}} air ais",
   "relative_time.full.just_now": "an-dràsta fhèin",
-  "relative_time.full.minutes": "{count, plural, one {# mhionaid} two {# mhionaid} few {# mionaidean} other {# mionaid}} air ais",
-  "relative_time.full.seconds": "{count, plural, one {# diog} two {# dhiog} few {# diogan} other {# diog}} air ais",
+  "relative_time.full.minutes": "{number, plural, one {# mhionaid} two {# mhionaid} few {# mionaidean} other {# mionaid}} air ais",
+  "relative_time.full.seconds": "{number, plural, one {# diog} two {# dhiog} few {# diogan} other {# diog}} air ais",
   "relative_time.hours": "{number}u",
   "relative_time.just_now": "an-dràsta",
   "relative_time.minutes": "{number}m",
@@ -436,11 +453,11 @@
   "report.thanks.title_actionable": "Mòran taing airson a’ ghearain, bheir sinn sùil air.",
   "report.unfollow": "Na lean air @{name} tuilleadh",
   "report.unfollow_explanation": "Tha thu a’ leantainn air a’ chunntas seo. Sgur de leantainn orra ach nach fhaic thu na puist aca air inbhir na dachaigh agad.",
-  "report_notification.attached_statuses": "{count, plural, one {{count} post} other {{count} posts}} attached",
-  "report_notification.categories.other": "Other",
-  "report_notification.categories.spam": "Spam",
-  "report_notification.categories.violation": "Rule violation",
-  "report_notification.open": "Open report",
+  "report_notification.attached_statuses": "Tha {count, plural, one {{counter} phost} two {{counter} phost} few {{counter} postaichean} other {{counter} post}} ceangailte ris",
+  "report_notification.categories.other": "Eile",
+  "report_notification.categories.spam": "Spama",
+  "report_notification.categories.violation": "Briseadh riaghailte",
+  "report_notification.open": "Fosgail an gearan",
   "search.placeholder": "Lorg",
   "search_popout.search_format": "Fòrmat adhartach an luirg",
   "search_popout.tips.full_text": "Bheir teacsa sìmplidh dhut na postaichean a sgrìobh thu, a tha nan annsachdan dhut, a bhrosnaich thu no san deach iomradh a thoirt ort cho math ri ainmean-cleachdaiche, ainmean taisbeanaidh agus tagaichean hais a mhaidsicheas.",
@@ -470,8 +487,9 @@
   "status.edited_x_times": "Chaidh a dheasachadh {count, plural, one {{counter} turas} two {{counter} thuras} few {{counter} tursan} other {{counter} turas}}",
   "status.embed": "Leabaich",
   "status.favourite": "Cuir ris na h-annsachdan",
+  "status.filter": "Filter this post",
   "status.filtered": "Criathraichte",
-  "status.hide": "Hide toot",
+  "status.hide": "Falaich am post",
   "status.history.created": "Chruthaich {name} {date} e",
   "status.history.edited": "Dheasaich {name} {date} e",
   "status.load_more": "Luchdaich barrachd dheth",
@@ -495,7 +513,7 @@
   "status.report": "Dèan gearan mu @{name}",
   "status.sensitive_warning": "Susbaint fhrionasach",
   "status.share": "Co-roinn",
-  "status.show_filter_reason": "Show anyway",
+  "status.show_filter_reason": "Seall e co-dhiù",
   "status.show_less": "Seall nas lugha dheth",
   "status.show_less_all": "Seall nas lugha dhen a h-uile",
   "status.show_more": "Seall barrachd dheth",
@@ -520,7 +538,7 @@
   "timeline_hint.resources.followers": "Luchd-leantainn",
   "timeline_hint.resources.follows": "A’ leantainn air",
   "timeline_hint.resources.statuses": "Postaichean nas sine",
-  "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
+  "trends.counter_by_accounts": "{count, plural, one {{counter} neach} two {{counter} neach} few {{counter} daoine} other {{counter} duine}} sna {days, plural, one {{days} latha} two {{days} latha} few {{days} làithean} other {{days} latha}} seo chaidh",
   "trends.trending_now": "A’ treandadh an-dràsta",
   "ui.beforeunload": "Caillidh tu an dreachd agad ma dh’fhàgas tu Mastodon an-dràsta.",
   "units.short.billion": "{count}B",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 56ceb54e8..0c7baa332 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Vaites!",
   "announcement.announcement": "Anuncio",
   "attachments_list.unprocessed": "(sen procesar)",
+  "audio.hide": "Agochar audio",
   "autosuggest_hashtag.per_week": "{count} por semana",
   "boost_modal.combo": "Preme {combo} para ignorar isto na seguinte vez",
   "bundle_column_error.body": "Ocorreu un erro ó cargar este compoñente.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Novas",
   "explore.trending_statuses": "Publicacións",
   "explore.trending_tags": "Cancelos",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Feito",
   "follow_recommendations.heading": "Segue a persoas das que queiras ler publicacións! Aqui tes unhas suxestións.",
   "follow_recommendations.lead": "As publicacións das persoas que segues aparecerán na túa cronoloxía de inicio ordenadas temporalmente. Non teñas medo a equivocarte, podes deixar de seguirlas igual de fácil en calquera momento!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Calquera destes",
   "hashtag.column_settings.tag_mode.none": "Ningún destes",
   "hashtag.column_settings.tag_toggle": "Incluír cancelos adicionais para esta columna",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Seguir cancelo",
   "hashtag.total_volume": "Cantidade total {days, plural, one {no último día} other {nos {days} últimos días}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Deixar de seguir cancelo",
   "home.column_settings.basic": "Básico",
   "home.column_settings.show_reblogs": "Amosar compartidos",
   "home.column_settings.show_replies": "Amosar respostas",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} veces}}",
   "status.embed": "Incrustar",
   "status.favourite": "Favorito",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrado",
   "status.hide": "Agochar publicación",
   "status.history.created": "{name} creouno o {date}",
@@ -520,7 +538,7 @@
   "timeline_hint.resources.followers": "Seguidoras",
   "timeline_hint.resources.follows": "Seguindo",
   "timeline_hint.resources.statuses": "Publicacións antigas",
-  "trends.counter_by_accounts": "{count, plural, one {{counter} persoa} other {{counter} persoas}} nos últimos {days, plural, one {día} other {{days} días}}",
+  "trends.counter_by_accounts": "{count, plural, one {{counter} persoa} other {{counter} persoas}} {days, plural, one {no último día} other {nos {days} últimos días}}",
   "trends.trending_now": "Tendencias actuais",
   "ui.beforeunload": "O borrador perderase se saes de Mastodon.",
   "units.short.billion": "{count}B",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index 4cb3380b4..281b91bc1 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "אופס!",
   "announcement.announcement": "הכרזה",
   "attachments_list.unprocessed": "(לא מעובד)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} לשבוע",
   "boost_modal.combo": "ניתן להקיש {combo} כדי לדלג בפעם הבאה",
   "bundle_column_error.body": "משהו השתבש בעת טעינת הרכיב הזה.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "חדשות",
   "explore.trending_statuses": "פוסטים",
   "explore.trending_tags": "האשטאגים",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "בוצע",
   "follow_recommendations.heading": "עקב/י אחרי אנשים שתרצה/י לראות את חצרוציהם! הנה כמה הצעות.",
   "follow_recommendations.lead": "חצרוצים מאנשים במעקב יופיעו בסדר כרונולוגי בפיד הבית. אל תחששו מטעויות, אפשר להסיר מעקב באותה הקלות ובכל זמן!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "כל אלה",
   "hashtag.column_settings.tag_mode.none": "אף אחד מאלה",
   "hashtag.column_settings.tag_toggle": "כלול תגיות נוספות בטור זה",
-  "hashtag.follow": "Follow hashtag",
-  "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.follow": "מעקב אחר תגית",
+  "hashtag.total_volume": "נפח כולל ב {days, plural, one {יום} other {{days} ימים}} האחרונים",
+  "hashtag.unfollow": "ביטול מעקב אחר תגית",
   "home.column_settings.basic": "למתחילים",
   "home.column_settings.show_reblogs": "הצגת הדהודים",
   "home.column_settings.show_replies": "הצגת תגובות",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "נערך {count, plural, one {פעם {count}} other {{count} פעמים}}",
   "status.embed": "הטמעה",
   "status.favourite": "חיבוב",
+  "status.filter": "Filter this post",
   "status.filtered": "סונן",
   "status.hide": "הסתר פוסט",
   "status.history.created": "{name} יצר/ה {date}",
diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json
index aa76ebf10..d2403c1f5 100644
--- a/app/javascript/mastodon/locales/hi.json
+++ b/app/javascript/mastodon/locales/hi.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "उफ़!",
   "announcement.announcement": "घोषणा",
   "attachments_list.unprocessed": "(असंसाधित)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} हर सप्ताह",
   "boost_modal.combo": "अगली बार स्किप करने के लिए आप {combo} दबा सकते है",
   "bundle_column_error.body": "इस कॉम्पोनेन्ट को लोड करते वक्त कुछ गलत हो गया",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json
index fe0379f0a..c66de9c0d 100644
--- a/app/javascript/mastodon/locales/hr.json
+++ b/app/javascript/mastodon/locales/hr.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ups!",
   "announcement.announcement": "Najava",
   "attachments_list.unprocessed": "(neobrađeno)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} tjedno",
   "boost_modal.combo": "Možete pritisnuti {combo} kako biste preskočili ovo sljedeći put",
   "bundle_column_error.body": "Nešto je pošlo po zlu tijekom učitavanja ove komponente.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Učinjeno",
   "follow_recommendations.heading": "Zaprati osobe čije objave želiš vidjeti! Evo nekoliko prijedloga.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Označi favoritom",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index def9348ec..ce25cd103 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Hoppá!",
   "announcement.announcement": "Közlemény",
   "attachments_list.unprocessed": "(feldolgozatlan)",
+  "audio.hide": "Hang elrejtése",
   "autosuggest_hashtag.per_week": "{count} hetente",
   "boost_modal.combo": "Hogy átugord ezt következő alkalommal, használd {combo}",
   "bundle_column_error.body": "Valami hiba történt a komponens betöltése közben.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Hírek",
   "explore.trending_statuses": "Bejegyzések",
   "explore.trending_tags": "Hashtagek",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Kész",
   "follow_recommendations.heading": "Kövesd azokat, akiknek a bejegyzéseit látni szeretnéd! Itt van néhány javaslat.",
   "follow_recommendations.lead": "Az általad követettek bejegyzései a saját idővonaladon fognak megjelenni időrendi sorrendben. Ne félj attól, hogy hibázol! A követést bármikor, ugyanilyen könnyen visszavonhatod!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Bármelyik",
   "hashtag.column_settings.tag_mode.none": "Egyik sem",
   "hashtag.column_settings.tag_toggle": "Új címkék felvétele ehhez az oszlophoz",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Hashtag követése",
   "hashtag.total_volume": "Teljes mennyiség az elmúlt {days, plural, one {napban} other {{days} napban}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Hashtag követésének megszüntetése",
   "home.column_settings.basic": "Alapvető",
   "home.column_settings.show_reblogs": "Megtolások mutatása",
   "home.column_settings.show_replies": "Válaszok megjelenítése",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "{count, plural, one {{count} alkalommal} other {{count} alkalommal}} szerkesztve",
   "status.embed": "Beágyazás",
   "status.favourite": "Kedvenc",
+  "status.filter": "Filter this post",
   "status.filtered": "Megszűrt",
   "status.hide": "Bejegyzés elrejtése",
   "status.history.created": "{name} létrehozta: {date}",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index 9aa8ec4c3..5a18eff04 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Վա՜յ",
   "announcement.announcement": "Յայտարարութիւններ",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "շաբաթը՝ {count}",
   "boost_modal.combo": "Կարող ես սեղմել {combo}՝ սա յաջորդ անգամ բաց թողնելու համար",
   "bundle_column_error.body": "Այս բաղադրիչը բեռնելու ընթացքում ինչ֊որ բան խափանուեց։",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Նորութիւններ",
   "explore.trending_statuses": "Գրառումներ",
   "explore.trending_tags": "Պիտակներ",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Աւարտուած է",
   "follow_recommendations.heading": "Հետեւիր այն մարդկանց, որոնց գրառումները կը ցանկանաս տեսնել։ Ահա մի քանի առաջարկ։",
   "follow_recommendations.lead": "Քո հոսքում, ժամանակագրական դասաւորութեամբ կը տեսնես այն մարդկանց գրառումները, որոնց հետեւում ես։ Մի վախեցիր սխալուել, դու միշտ կարող ես հեշտութեամբ ապահետեւել մարդկանց։",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Ներդնել",
   "status.favourite": "Հաւանել",
+  "status.filter": "Filter this post",
   "status.filtered": "Զտուած",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index effc01737..9c3879212 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ups!",
   "announcement.announcement": "Pengumuman",
   "attachments_list.unprocessed": "(tidak diproses)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} per minggu",
   "boost_modal.combo": "Anda dapat menekan {combo} untuk melewati ini",
   "bundle_column_error.body": "Kesalahan terjadi saat memuat komponen ini.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Berita",
   "explore.trending_statuses": "Postingan",
   "explore.trending_tags": "Tagar",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Selesai",
   "follow_recommendations.heading": "Ikuti orang yang ingin Anda lihat kirimannya! Ini ada beberapa saran.",
   "follow_recommendations.lead": "Kiriman dari orang yang Anda ikuti akan tampil berdasar waktu di beranda Anda. Jangan takut membuat kesalahan, Anda dapat berhenti mengikuti mereka dengan mudah kapan saja!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Diedit {count, plural, other {{count} kali}}",
   "status.embed": "Tanam",
   "status.favourite": "Difavoritkan",
+  "status.filter": "Filter this post",
   "status.filtered": "Disaring",
   "status.hide": "Hide toot",
   "status.history.created": "{name} membuat pada {date}",
diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json
index d54687117..f3bdb040c 100644
--- a/app/javascript/mastodon/locales/io.json
+++ b/app/javascript/mastodon/locales/io.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Problemo!",
   "announcement.announcement": "Anunco",
   "attachments_list.unprocessed": "(neprocedita)",
+  "audio.hide": "Celez audio",
   "autosuggest_hashtag.per_week": "{count} dum singla semano",
   "boost_modal.combo": "Tu povas presar sur {combo} por omisar co en la venonta foyo",
   "bundle_column_error.body": "Nulo ne functionis dum chargar ca kompozaj.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Niuzi",
   "explore.trending_statuses": "Posti",
   "explore.trending_tags": "Hashtagi",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Fina",
   "follow_recommendations.heading": "Sequez personi quo igas posti quon vu volas vidar! Hike esas ula sugestati.",
   "follow_recommendations.lead": "Posti de personi quon vu sequas kronologiale montresos en vua hemniuzeto. Ne timas igar erori, vu povas desequar personi tam same facila irgatempe!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Irga co",
   "hashtag.column_settings.tag_mode.none": "Nula co",
   "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Sequez hashtago",
   "hashtag.total_volume": "Sumo en antea {days, plural,one {dio} other {{days} dii}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Desequez hashtago",
   "home.column_settings.basic": "Simpla",
   "home.column_settings.show_reblogs": "Montrar repeti",
   "home.column_settings.show_replies": "Montrar respondi",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Modifikesis {count, plural, one {{count} foyo} other {{count} foyi}}",
   "status.embed": "Eninsertez",
   "status.favourite": "Favorizar",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrita",
   "status.hide": "Celez posto",
   "status.history.created": "{name} kreis ye {date}",
diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json
index e12bfe305..7e3a40fa7 100644
--- a/app/javascript/mastodon/locales/is.json
+++ b/app/javascript/mastodon/locales/is.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Úbbs!",
   "announcement.announcement": "Auglýsing",
   "attachments_list.unprocessed": "(óunnið)",
+  "audio.hide": "Fela hljóð",
   "autosuggest_hashtag.per_week": "{count} á viku",
   "boost_modal.combo": "Þú getur ýtt á {combo} til að sleppa þessu næst",
   "bundle_column_error.body": "Eitthvað fór úrskeiðis við að hlaða inn þessari einingu.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Fréttir",
   "explore.trending_statuses": "Færslur",
   "explore.trending_tags": "Myllumerki",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Lokið",
   "follow_recommendations.heading": "Fylgstu með fólki sem þú vilt sjá færslur frá! Hér eru nokkrar tillögur.",
   "follow_recommendations.lead": "Færslur frá fólki sem þú fylgist með eru birtar í tímaröð á heimastreyminu þínu. Þú þarft ekki að hræðast mistök, það er jafn auðvelt að hætta að fylgjast með fólki hvenær sem er!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Hvað sem er af þessu",
   "hashtag.column_settings.tag_mode.none": "Ekkert af þessu",
   "hashtag.column_settings.tag_toggle": "Taka með viðbótarmerki fyrir þennan dálk",
-  "hashtag.follow": "Follow hashtag",
-  "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.follow": "Fylgjast með myllumerki",
+  "hashtag.total_volume": "Heildarmagn {days, plural, one {síðasta {days} sólarhring} other {síðustu {days} daga}}",
+  "hashtag.unfollow": "Hætta að fylgjast með myllumerki",
   "home.column_settings.basic": "Einfalt",
   "home.column_settings.show_reblogs": "Sýna endurbirtingar",
   "home.column_settings.show_replies": "Birta svör",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Breytt {count, plural, one {{count} sinni} other {{count} sinnum}}",
   "status.embed": "Ívefja",
   "status.favourite": "Eftirlæti",
+  "status.filter": "Filter this post",
   "status.filtered": "Síað",
   "status.hide": "Fela færslu",
   "status.history.created": "{name} útbjó {date}",
@@ -520,7 +538,7 @@
   "timeline_hint.resources.followers": "Fylgjendur",
   "timeline_hint.resources.follows": "Fylgist með",
   "timeline_hint.resources.statuses": "Eldri færslur",
-  "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
+  "trends.counter_by_accounts": "{count, plural, one {{counter} aðili} other {{counter} manns}} {days, plural, one {síðasta sólarhringinn} other {síðustu {days} daga}}",
   "trends.trending_now": "Í umræðunni núna",
   "ui.beforeunload": "Drögin tapast ef þú ferð út úr Mastodon.",
   "units.short.billion": "{count}B",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index da29dfde1..9f32a0685 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Annuncio",
   "attachments_list.unprocessed": "(non elaborato)",
+  "audio.hide": "Nascondi audio",
   "autosuggest_hashtag.per_week": "{count} per settimana",
   "boost_modal.combo": "Puoi premere {combo} per saltare questo passaggio la prossima volta",
   "bundle_column_error.body": "E' avvenuto un errore durante il caricamento di questo componente.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Novità",
   "explore.trending_statuses": "Post",
   "explore.trending_tags": "Hashtag",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Fatto",
   "follow_recommendations.heading": "Segui le persone da cui vuoi vedere i messaggi! Ecco alcuni suggerimenti.",
   "follow_recommendations.lead": "I messaggi da persone che segui verranno visualizzati in ordine cronologico nel tuo home feed. Non abbiate paura di commettere errori, potete smettere di seguire le persone altrettanto facilmente in qualsiasi momento!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Uno o più di questi",
   "hashtag.column_settings.tag_mode.none": "Nessuno di questi",
   "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Segui l'hashtag",
   "hashtag.total_volume": "Volume totale {days, plural, one {nell'ultimo giorno} other {negli ultimi {days} giorni}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Cessa di seguire l'hashtag",
   "home.column_settings.basic": "Semplice",
   "home.column_settings.show_reblogs": "Mostra condivisioni",
   "home.column_settings.show_replies": "Mostra risposte",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Modificato {count, plural, one {{count} volta} other {{count} volte}}",
   "status.embed": "Incorpora",
   "status.favourite": "Apprezzato",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrato",
   "status.hide": "Nascondi toot",
   "status.history.created": "{name} ha creato {date}",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 8e1746a07..2b3513693 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "エラー!",
   "announcement.announcement": "お知らせ",
   "attachments_list.unprocessed": "(未処理)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} 回 / 週",
   "boost_modal.combo": "次からは{combo}を押せばスキップできます",
   "bundle_column_error.body": "コンポーネントの読み込み中に問題が発生しました。",
@@ -200,6 +201,22 @@
   "explore.trending_links": "ニュース",
   "explore.trending_statuses": "投稿",
   "explore.trending_tags": "ハッシュタグ",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "完了",
   "follow_recommendations.heading": "投稿を見たい人をフォローしてください!ここにおすすめがあります。",
   "follow_recommendations.lead": "あなたがフォローしている人の投稿は、ホームフィードに時系列で表示されます。いつでも簡単に解除できるので、気軽にフォローしてみてください!",
@@ -224,9 +241,9 @@
   "hashtag.column_settings.tag_mode.any": "いずれかを含む",
   "hashtag.column_settings.tag_mode.none": "これらを除く",
   "hashtag.column_settings.tag_toggle": "このカラムに追加のタグを含める",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "ハッシュタグをフォローする",
   "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "ハッシュタグのフォローを解除",
   "home.column_settings.basic": "基本設定",
   "home.column_settings.show_reblogs": "ブースト表示",
   "home.column_settings.show_replies": "返信表示",
@@ -475,6 +492,7 @@
   "status.edited_x_times": "{count}回編集",
   "status.embed": "埋め込み",
   "status.favourite": "お気に入り",
+  "status.filter": "Filter this post",
   "status.filtered": "フィルターされました",
   "status.hide": "トゥートを非表示",
   "status.history.created": "{name}さんが{date}に作成",
diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json
index a01b2290c..c6c72b6ce 100644
--- a/app/javascript/mastodon/locales/ka.json
+++ b/app/javascript/mastodon/locales/ka.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "უპს!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "კვირაში {count}",
   "boost_modal.combo": "შეგიძლიათ დააჭიროთ {combo}-ს რათა შემდეგ ჯერზე გამოტოვოთ ეს",
   "bundle_column_error.body": "ამ კომპონენტის ჩატვირთვისას რაღაც აირია.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "ჩართვა",
   "status.favourite": "ფავორიტი",
+  "status.filter": "Filter this post",
   "status.filtered": "ფილტრირებული",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json
index d5ab20008..035ec7c84 100644
--- a/app/javascript/mastodon/locales/kab.json
+++ b/app/javascript/mastodon/locales/kab.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ayhuh!",
   "announcement.announcement": "Ulɣu",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} i yimalas",
   "boost_modal.combo": "Tzemreḍ ad tetekkiḍ ɣef {combo} akken ad tessurfeḍ aya tikelt-nniḍen",
   "bundle_column_error.body": "Tella-d kra n tuccḍa mi d-yettali ugbur-agi.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Tisuffaɣ",
   "explore.trending_tags": "Ihacṭagen",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Immed",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Seddu",
   "status.favourite": "Rnu ɣer yismenyifen",
+  "status.filter": "Filter this post",
   "status.filtered": "Yettwasizdeg",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json
index 5334331c4..edcf0650c 100644
--- a/app/javascript/mastodon/locales/kk.json
+++ b/app/javascript/mastodon/locales/kk.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Өй!",
   "announcement.announcement": "Хабарландыру",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} аптасына",
   "boost_modal.combo": "Келесіде өткізіп жіберу үшін басыңыз {combo}",
   "bundle_column_error.body": "Бұл компонентті жүктеген кезде бір қате пайда болды.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embеd",
   "status.favourite": "Таңдаулы",
+  "status.filter": "Filter this post",
   "status.filtered": "Фильтрленген",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/kn.json b/app/javascript/mastodon/locales/kn.json
index bde13c04c..3d2e0a68d 100644
--- a/app/javascript/mastodon/locales/kn.json
+++ b/app/javascript/mastodon/locales/kn.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "ಅಯ್ಯೋ!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 30cf08ff2..e5dfc7689 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "앗!",
   "announcement.announcement": "공지사항",
   "attachments_list.unprocessed": "(처리 안 됨)",
+  "audio.hide": "소리 숨기기",
   "autosuggest_hashtag.per_week": "주간 {count}회",
   "boost_modal.combo": "다음엔 {combo}를 눌러서 이 과정을 건너뛸 수 있습니다",
   "bundle_column_error.body": "컴포넌트를 불러오는 과정에서 문제가 발생했습니다.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "소식",
   "explore.trending_statuses": "게시물",
   "explore.trending_tags": "해시태그",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "완료",
   "follow_recommendations.heading": "게시물을 받아 볼 사람들을 팔로우 하세요! 여기 몇몇의 추천이 있습니다.",
   "follow_recommendations.lead": "당신이 팔로우 하는 사람들의 게시물이 시간순으로 정렬되어 당신의 홈 피드에 표시될 것입니다. 실수를 두려워 하지 마세요, 언제든지 쉽게 팔로우 취소를 할 수 있습니다!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "아무것이든",
   "hashtag.column_settings.tag_mode.none": "이것들을 제외하고",
   "hashtag.column_settings.tag_toggle": "추가 해시태그를 이 컬럼에 추가합니다",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "해시태그 팔로우",
   "hashtag.total_volume": "최근 {days}일 동안의 총 사용량",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "해시태그 팔로우 해제",
   "home.column_settings.basic": "기본",
   "home.column_settings.show_reblogs": "부스트 표시",
   "home.column_settings.show_replies": "답글 표시",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "{count}번 수정됨",
   "status.embed": "공유하기",
   "status.favourite": "좋아요",
+  "status.filter": "Filter this post",
   "status.filtered": "필터로 걸러짐",
   "status.hide": "툿 숨기기",
   "status.history.created": "{name} 님이 {date}에 생성함",
diff --git a/app/javascript/mastodon/locales/ku.json b/app/javascript/mastodon/locales/ku.json
index d8c4151d3..27033efbf 100644
--- a/app/javascript/mastodon/locales/ku.json
+++ b/app/javascript/mastodon/locales/ku.json
@@ -17,28 +17,28 @@
   "account.follow": "Bişopîne",
   "account.followers": "Şopîner",
   "account.followers.empty": "Kesekî hin ev bikarhêner neşopandiye.",
-  "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
+  "account.followers_counter": "{count, plural, one {{counter} Şopîner} other {{counter} Şopîner}}",
   "account.following": "Dişopîne",
   "account.following_counter": "{count, plural, one {{counter} Dişopîne} other {{counter} Dişopîne}}",
   "account.follows.empty": "Ev bikarhêner hin kesekî heya niha neşopandiye.",
   "account.follows_you": "Te dişopîne",
   "account.hide_reblogs": "Bilindkirinên ji @{name} veşêre",
-  "account.joined": "Tevlîbû di {date} de",
+  "account.joined": "Di {date} de tevlî bû",
   "account.link_verified_on": "Xwedaniya li vê girêdanê di {date} de hatiye kontrolkirin",
   "account.locked_info": "Rewşa vê ajimêrê wek kilît kirî hatiye saz kirin. Xwedî yê ajimêrê, kesên vê bişopîne bi dest vekolin dike.",
   "account.media": "Medya",
   "account.mention": "Qal @{name} bike",
   "account.moved_to": "{name} hate livandin bo:",
-  "account.mute": "@{name} Bêdeng bike",
+  "account.mute": "@{name} bêdeng bike",
   "account.mute_notifications": "Agahdariyan ji @{name} bêdeng bike",
   "account.muted": "Bêdengkirî",
   "account.posts": "Şandî",
   "account.posts_with_replies": "Şandî û bersiv",
-  "account.report": "@{name} Ragihîne",
+  "account.report": "@{name} ragihîne",
   "account.requested": "Li benda erêkirinê ye. Ji bo betal kirina daxwazê pêl bikin",
   "account.share": "Profîla @{name} parve bike",
   "account.show_reblogs": "Bilindkirinên ji @{name} nîşan bike",
-  "account.statuses_counter": "{count, plural,one {{counter} şandî}other {{counter} şandî}}",
+  "account.statuses_counter": "{count, plural,one {{counter} Şandî}other {{counter} Şandî}}",
   "account.unblock": "Astengê li ser @{name} rake",
   "account.unblock_domain": "Astengê li ser navperê {domain} rake",
   "account.unblock_short": "Astengiyê rake",
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Wey li min!",
   "announcement.announcement": "Daxuyanî",
   "attachments_list.unprocessed": "(bêpêvajo)",
+  "audio.hide": "Dengê veşêre",
   "autosuggest_hashtag.per_week": "Her hefte {count}",
   "boost_modal.combo": "Ji bo derbas bî carekî din de pêlê {combo} bike",
   "bundle_column_error.body": "Di dema barkirina vê hêmanê de tiştek çewt çê bû.",
@@ -75,12 +76,12 @@
   "column.domain_blocks": "Navperên astengkirî",
   "column.favourites": "Bijarte",
   "column.follow_requests": "Daxwazên şopandinê",
-  "column.home": "Serrûpel",
+  "column.home": "Rûpela sereke",
   "column.lists": "Rêzok",
   "column.mutes": "Bikarhênerên bêdengkirî",
   "column.notifications": "Agahdarî",
   "column.pins": "Şandiya derzîkirî",
-  "column.public": "Demnameyê federalîkirî",
+  "column.public": "Demnameya giştî",
   "column_back_button.label": "Vegere",
   "column_header.hide_settings": "Sazkariyan veşêre",
   "column_header.moveLeft_settings": "Stûnê bilivîne bo çepê",
@@ -167,12 +168,12 @@
   "empty_column.account_timeline": "Li vir şandî tune!",
   "empty_column.account_unavailable": "Profîl nayê peydakirin",
   "empty_column.blocks": "Te tu bikarhêner asteng nekiriye.",
-  "empty_column.bookmarked_statuses": "Hîn tu peyamên şûnpelkirî tuneye. Gava ku hûn yek şûnpel bikin, ew ê li vir xûya bike.",
+  "empty_column.bookmarked_statuses": "Hîn tu peyamên te yên şûnpelkirî tune ne. Dema ku tu yekî şûnpel bikî, ew ê li vir xuya bibe.",
   "empty_column.community": "Demnameya herêmî vala ye. Tiştek ji raya giştî re binivsînin da ku rûpel biherike!",
-  "empty_column.direct": "Hêj peyameke te yê rasterast tuneye. Gava ku tu yekî bişeynî an jî bigirî, ew ê li vir xûya bike.",
+  "empty_column.direct": "Hîn peyamên te yên rasterast tune ne. Dema ku tu yekî bişînî an jî wergirî, ew ê li vir xuya bibe.",
   "empty_column.domain_blocks": "Hê jî navperên hatine asteng kirin tune ne.",
   "empty_column.explore_statuses": "Tiştek niha di rojevê de tune. Paşê vegere!",
-  "empty_column.favourited_statuses": "Hîn tu peyamên te yên bijare tunene. Gava ku te yekî bijart, ew ê li vir xûya bike.",
+  "empty_column.favourited_statuses": "Hîn tu peyamên te yên bijarte tune ne. Dema ku te yekî bijart, ew ê li vir xuya bibe.",
   "empty_column.favourites": "Hîn tu kes vê peyamê nebijartiye. Gava ku hin kes bijartin, ew ê li vir xûya bikin.",
   "empty_column.follow_recommendations": "Wusa dixuye ku ji bo we tu pêşniyar nehatine çêkirin. Hûn dikarin lêgerînê bikarbînin da ku li kesên ku hûn nas dikin bigerin an hashtagên trendî bigerin.",
   "empty_column.follow_requests": "Hê jî daxwaza şopandinê tunne ye. Dema daxwazek hat, yê li vir were nîşan kirin.",
@@ -180,7 +181,7 @@
   "empty_column.home": "Demnameya mala we vala ye! Ji bona tijîkirinê bêtir mirovan bişopînin. {suggestions}",
   "empty_column.home.suggestions": "Hinek pêşniyaran bibîne",
   "empty_column.list": "Di vê rêzokê de hîn tiştek tune ye. Gava ku endamên vê rêzokê peyamên nû biweşînin, ew ê li vir xuya bibin.",
-  "empty_column.lists": "Hêj qet rêzokê te tunne ye. Dema yek peyda bû, yê li vir were nîşan kirin.",
+  "empty_column.lists": "Hîn tu rêzokên te tune ne. Dema yekî çê bikî, ew ê li vir xuya bibe.",
   "empty_column.mutes": "Te tu bikarhêner bêdeng nekiriye.",
   "empty_column.notifications": "Hêj hişyariyên te tunene. Dema ku mirovên din bi we re têkilî danîn, hûn ê wê li vir bibînin.",
   "empty_column.public": "Li vir tiştekî tuneye! Ji raya giştî re tiştekî binivîsîne, an ji bo tijîkirinê ji rajekerên din bikarhêneran bi destan bişopînin",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Nûçe",
   "explore.trending_statuses": "Şandî",
   "explore.trending_tags": "Hashtag",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Qediya",
   "follow_recommendations.heading": "Mirovên ku tu dixwazî ji wan peyaman bibînî bişopîne! Hin pêşnîyar li vir in.",
   "follow_recommendations.lead": "Li gorî rêza kronolojîkî peyamên mirovên ku tu dişopînî dê demnameya te de xûya bike. Ji xeletiyan netirse, bi awayekî hêsan her wextî tu dikarî dev ji şopandinê berdî!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Yek ji van",
   "hashtag.column_settings.tag_mode.none": "Ne yek ji van",
   "hashtag.column_settings.tag_toggle": "Ji bo vê stûnê hin pêvekan tevlî bike",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Hashtagê bişopîne",
   "hashtag.total_volume": "Tevahiya giraniyê dawîn di {days, plural, one {roj} other {{days} roj}} de",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Hashtagê neşopîne",
   "home.column_settings.basic": "Bingehîn",
   "home.column_settings.show_reblogs": "Bilindkirinan nîşan bike",
   "home.column_settings.show_replies": "Bersivan nîşan bide",
@@ -242,10 +259,10 @@
   "keyboard_shortcuts.enter": "Şandiyê veke",
   "keyboard_shortcuts.favourite": "Şandiya bijarte",
   "keyboard_shortcuts.favourites": "Rêzokên bijarte veke",
-  "keyboard_shortcuts.federated": "Demnameyê federalîkirî veke",
+  "keyboard_shortcuts.federated": "Demnameya giştî veke",
   "keyboard_shortcuts.heading": "Kurterêyên klavyeyê",
   "keyboard_shortcuts.home": "Demnameyê veke",
-  "keyboard_shortcuts.hotkey": "Bişkoka kurterê",
+  "keyboard_shortcuts.hotkey": "Kurte bişkok",
   "keyboard_shortcuts.legend": "Vê çîrokê nîşan bike",
   "keyboard_shortcuts.local": "Demnameya herêmî veke",
   "keyboard_shortcuts.mention": "Qala nivîskarî/ê bike",
@@ -271,7 +288,7 @@
   "lightbox.next": "Pêş",
   "lightbox.previous": "Paş",
   "limited_account_hint.action": "Bi heman awayî profîlê nîşan bide",
-  "limited_account_hint.title": "Ev profîl ji aliyê çavêriya li ser rajekarê te hatiye veşartin.",
+  "limited_account_hint.title": "Ev profîl ji aliyê çavdêriya li ser rajekarê te hatiye veşartin.",
   "lists.account.add": "Tevlî rêzokê bike",
   "lists.account.remove": "Ji rêzokê rake",
   "lists.delete": "Rêzokê jê bibe",
@@ -293,7 +310,7 @@
   "mute_modal.duration": "Dem",
   "mute_modal.hide_notifications": "Agahdariyan ji ev bikarhêner veşêre?",
   "mute_modal.indefinite": "Nediyar",
-  "navigation_bar.apps": "Sepana mobîl",
+  "navigation_bar.apps": "Sepana mobayil",
   "navigation_bar.blocks": "Bikarhênerên astengkirî",
   "navigation_bar.bookmarks": "Şûnpel",
   "navigation_bar.community_timeline": "Demnameya herêmî",
@@ -308,14 +325,14 @@
   "navigation_bar.follow_requests": "Daxwazên şopandinê",
   "navigation_bar.follows_and_followers": "Şopandin û şopîner",
   "navigation_bar.info": "Derbarê vî rajekarî",
-  "navigation_bar.keyboard_shortcuts": "Bişkoka kurterê",
+  "navigation_bar.keyboard_shortcuts": "Kurte bişkok",
   "navigation_bar.lists": "Rêzok",
   "navigation_bar.logout": "Derkeve",
   "navigation_bar.mutes": "Bikarhênerên bêdengkirî",
   "navigation_bar.personal": "Kesanî",
   "navigation_bar.pins": "Şandiya derzîkirî",
   "navigation_bar.preferences": "Sazkarî",
-  "navigation_bar.public_timeline": "Demnameyê federalîkirî",
+  "navigation_bar.public_timeline": "Demnameya giştî",
   "navigation_bar.security": "Ewlehî",
   "notification.admin.report": "{name} hate ragihandin {target}",
   "notification.admin.sign_up": "{name} tomar bû",
@@ -386,7 +403,7 @@
   "privacy.unlisted.short": "Nerêzok",
   "refresh": "Nû bike",
   "regeneration_indicator.label": "Tê barkirin…",
-  "regeneration_indicator.sublabel": "Mala te da tê amedekirin!",
+  "regeneration_indicator.sublabel": "Naveroka rûpela sereke ya te tê amedekirin!",
   "relative_time.days": "{number}r",
   "relative_time.full.days": "{number, plural, one {# roj} other {# roj}} berê",
   "relative_time.full.hours": "{number, plural, one {# demjimêr} other {# demjimêr}} berê",
@@ -411,7 +428,7 @@
   "report.close": "Qediya",
   "report.comment.title": "Tiştek din heye ku tu difikirî ku divê em zanibin?",
   "report.forward": "Biçe bo {target}",
-  "report.forward_hint": "Ajimêr ji rajekarek din da ne. Tu kopîyeka anonîm ya raporê bişînî li wur?",
+  "report.forward_hint": "Ajimêr ji rajekareke din e. Tu kopîyeka anonîm ya raporê bişînî wir jî?",
   "report.mute": "Bêdeng bike",
   "report.mute_explanation": "Tê yê şandiyên wan nebînî. Ew hin jî dikarin te bişopînin û şandiyên te bibînin û wê nizanibin ku ew hatine bêdengkirin.",
   "report.next": "Pêş",
@@ -436,7 +453,7 @@
   "report.thanks.title_actionable": "Spas ji bo ragihandina te, em ê binirxînin.",
   "report.unfollow": "@{name} neşopîne",
   "report.unfollow_explanation": "Tê vê ajimêrê dişopînî. Ji bo ku êdî şandiyên wan di rojeva xwe de nebînî, wan neşopîne.",
-  "report_notification.attached_statuses": "{count, plural,one {{count} şandî} other {{count} şandî }} pêvekirî",
+  "report_notification.attached_statuses": "{count, plural,one {{count} şandî} other {{count} şandî}} pêvekirî",
   "report_notification.categories.other": "Ên din",
   "report_notification.categories.spam": "Nexwestî (Spam)",
   "report_notification.categories.violation": "Binpêkirina rêzîkê",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "{count, plural, one {{count} car} other {{count} car}} hate serrastkirin",
   "status.embed": "Hedimandî",
   "status.favourite": "Bijarte",
+  "status.filter": "Filter this post",
   "status.filtered": "Parzûnkirî",
   "status.hide": "Şandiyê veşêre",
   "status.history.created": "{name} {date} afirand",
@@ -492,13 +510,13 @@
   "status.remove_bookmark": "Şûnpêlê jê rake",
   "status.reply": "Bersivê bide",
   "status.replyAll": "Mijarê bibersivîne",
-  "status.report": "{name} gilî bike",
+  "status.report": "@{name} ragihîne",
   "status.sensitive_warning": "Naveroka hestiyarî",
   "status.share": "Parve bike",
   "status.show_filter_reason": "Bi her awayî nîşan bide",
   "status.show_less": "Kêmtir nîşan bide",
   "status.show_less_all": "Ji bo hemîyan kêmtir nîşan bide",
-  "status.show_more": "Hêj zehftir nîşan bide",
+  "status.show_more": "Bêtir nîşan bide",
   "status.show_more_all": "Bêtir nîşan bide bo hemûyan",
   "status.show_thread": "Mijarê nîşan bide",
   "status.uncached_media_warning": "Tune ye",
@@ -507,7 +525,7 @@
   "suggestions.dismiss": "Pêşniyarê paşguh bike",
   "suggestions.header": "Dibe ku bala te bikşîne…",
   "tabs_bar.federated_timeline": "Giştî",
-  "tabs_bar.home": "Serrûpel",
+  "tabs_bar.home": "Rûpela sereke",
   "tabs_bar.local_timeline": "Herêmî",
   "tabs_bar.notifications": "Agahdarî",
   "tabs_bar.search": "Bigere",
diff --git a/app/javascript/mastodon/locales/kw.json b/app/javascript/mastodon/locales/kw.json
index 988655921..f6a85a932 100644
--- a/app/javascript/mastodon/locales/kw.json
+++ b/app/javascript/mastodon/locales/kw.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oups!",
   "announcement.announcement": "Deklaryans",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} an seythen",
   "boost_modal.combo": "Hwi a yll gwaska {combo} dhe woheles hemma an nessa tro",
   "bundle_column_error.body": "Neppyth eth yn kamm ow karga'n elven ma.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Gwrys",
   "follow_recommendations.heading": "Holyewgh tus a vynnowgh gweles postow anedha! Ottomma nebes profyansow.",
   "follow_recommendations.lead": "Postow a dus a holyewgh a wra omdhiskwedhes omma yn aray termynel yn agas lin dre. Na borthewgh own a gammwul, hwi a yll p'eurpynag anholya tus mar es poran!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Staga",
   "status.favourite": "Merkya vel drudh",
+  "status.filter": "Filter this post",
   "status.filtered": "Sidhlys",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index 3df14c833..4e238273e 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oi!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json
index 1cb0095b1..1912dd7db 100644
--- a/app/javascript/mastodon/locales/lv.json
+++ b/app/javascript/mastodon/locales/lv.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ups!",
   "announcement.announcement": "Paziņojums",
   "attachments_list.unprocessed": "(neapstrādāti)",
+  "audio.hide": "Slēpt audio",
   "autosuggest_hashtag.per_week": "{count} nedēļā",
   "boost_modal.combo": "Nospied {combo} lai izlaistu šo nākamreiz",
   "bundle_column_error.body": "Kaut kas nogāja greizi ielādējot šo komponenti.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Jaunumi",
   "explore.trending_statuses": "Ziņas",
   "explore.trending_tags": "Tēmturi",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Izpildīts",
   "follow_recommendations.heading": "Seko cilvēkiem, no kuriem vēlies redzēt ziņas! Šeit ir daži ieteikumi.",
   "follow_recommendations.lead": "Ziņas no cilvēkiem, kuriem seko, mājas plūsmā tiks parādītas hronoloģiskā secībā. Nebaidies kļūdīties, tu tikpat viegli vari pārtraukt sekot cilvēkiem jebkurā laikā!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Kāds no šiem",
   "hashtag.column_settings.tag_mode.none": "Neviens no šiem",
   "hashtag.column_settings.tag_toggle": "Iekļaut šai kolonnai papildu tagus",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Seko mirkļbirkai",
   "hashtag.total_volume": "Kopējais apjoms par {days, plural, one {dienu} other {{days} dienām}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Pārstāj sekot mirkļbirkai",
   "home.column_settings.basic": "Pamata",
   "home.column_settings.show_reblogs": "Rādīt palielinājumus",
   "home.column_settings.show_replies": "Rādīt atbildes",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Rediģēts {count, plural, one {{count} reize} other {{count} reizes}}",
   "status.embed": "Iestrādāt",
   "status.favourite": "Iecienītā",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrēts",
   "status.hide": "Slēpt",
   "status.history.created": "{name} izveidots {date}",
diff --git a/app/javascript/mastodon/locales/mk.json b/app/javascript/mastodon/locales/mk.json
index faf4174f9..d782dff64 100644
--- a/app/javascript/mastodon/locales/mk.json
+++ b/app/javascript/mastodon/locales/mk.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Упс!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} неделно",
   "boost_modal.combo": "Кликни {combo} за да го прескокниш ова нареден пат",
   "bundle_column_error.body": "Се случи проблем при вчитувањето.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/ml.json b/app/javascript/mastodon/locales/ml.json
index 175316e84..37969475d 100644
--- a/app/javascript/mastodon/locales/ml.json
+++ b/app/javascript/mastodon/locales/ml.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "ശ്ശോ!",
   "announcement.announcement": "അറിയിപ്പ്",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "ആഴ്ച തോറും {count}",
   "boost_modal.combo": "അടുത്ത തവണ ഇത് ഒഴിവാക്കുവാൻ {combo} ഞെക്കാവുന്നതാണ്",
   "bundle_column_error.body": "ഈ ഘടകം പ്രദശിപ്പിക്കുമ്പോൾ എന്തോ കുഴപ്പം സംഭവിച്ചു.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "പൂര്‍ത്തിയായീ",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "ഉൾച്ചേർക്കുക",
   "status.favourite": "പ്രിയപ്പെട്ടത്",
+  "status.filter": "Filter this post",
   "status.filtered": "ഫിൽട്ടർ ചെയ്‌തു",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/mr.json b/app/javascript/mastodon/locales/mr.json
index 762d94c40..09eaea3f9 100644
--- a/app/javascript/mastodon/locales/mr.json
+++ b/app/javascript/mastodon/locales/mr.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "अरेरे!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} प्रतिसप्ताह",
   "boost_modal.combo": "You can press {combo} to skip this next time",
   "bundle_column_error.body": "हा घटक लोड करतांना काहीतरी चुकले आहे.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json
index 13a1e3345..6a1302329 100644
--- a/app/javascript/mastodon/locales/ms.json
+++ b/app/javascript/mastodon/locales/ms.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Alamak!",
   "announcement.announcement": "Pengumuman",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} seminggu",
   "boost_modal.combo": "Anda boleh tekan {combo} untuk melangkauinya pada waktu lain",
   "bundle_column_error.body": "Terdapat kesilapan ketika memuatkan komponen ini.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Selesai",
   "follow_recommendations.heading": "Ikuti orang yang anda ingin lihat hantarannya! Di sini ada beberapa cadangan.",
   "follow_recommendations.lead": "Hantaran daripada orang yang anda ikuti akan muncul dalam susunan kronologi di suapan rumah anda. Jangan takut melakukan kesilapan, anda boleh nyahikuti orang dengan mudah pada bila-bila masa!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Benaman",
   "status.favourite": "Kegemaran",
+  "status.filter": "Filter this post",
   "status.filtered": "Ditapis",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index e98dc6379..df59ee3f7 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -51,7 +51,7 @@
   "admin.dashboard.daily_retention": "Retentiegraad van gebruikers per dag, vanaf registratie",
   "admin.dashboard.monthly_retention": "Retentiegraad van gebruikers per maand, vanaf registratie",
   "admin.dashboard.retention.average": "Gemiddelde",
-  "admin.dashboard.retention.cohort": "Aanmeldingsmaand",
+  "admin.dashboard.retention.cohort": "Maand van registratie",
   "admin.dashboard.retention.cohort_size": "Nieuwe gebruikers",
   "alert.rate_limited.message": "Probeer het nog een keer na {retry_time, time, medium}.",
   "alert.rate_limited.title": "Beperkt te gebruiken",
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oeps!",
   "announcement.announcement": "Mededeling",
   "attachments_list.unprocessed": "(niet verwerkt)",
+  "audio.hide": "Audio verbergen",
   "autosuggest_hashtag.per_week": "{count} per week",
   "boost_modal.combo": "Je kunt {combo} klikken om dit de volgende keer over te slaan",
   "bundle_column_error.body": "Tijdens het laden van dit onderdeel is er iets fout gegaan.",
@@ -172,8 +173,8 @@
   "empty_column.direct": "Je hebt nog geen directe berichten. Wanneer je er een verzend of ontvangt, komt deze hier te staan.",
   "empty_column.domain_blocks": "Er zijn nog geen geblokkeerde domeinen.",
   "empty_column.explore_statuses": "Momenteel zijn er geen trends. Kom later terug!",
-  "empty_column.favourited_statuses": "Jij hebt nog geen favoriete berichten. Wanneer je er een aan jouw favorieten toevoegt, valt deze hier te zien.",
-  "empty_column.favourites": "Niemand heeft dit bericht nog aan diens favorieten toegevoegd. Wanneer iemand dit doet, valt dat hier te zien.",
+  "empty_column.favourited_statuses": "Jij hebt nog geen favoriete berichten. Wanneer je een bericht als favoriet markeert, valt deze hier te zien.",
+  "empty_column.favourites": "Niemand heeft dit bericht nog als favoriet gemarkeerd. Wanneer iemand dit doet, valt dat hier te zien.",
   "empty_column.follow_recommendations": "Het lijkt er op dat er geen aanbevelingen voor jou aangemaakt kunnen worden. Je kunt proberen te zoeken naar mensen die je wellicht kent, zoeken op hashtags, de lokale en globale tijdlijnen bekijken of de gebruikersgids doorbladeren.",
   "empty_column.follow_requests": "Jij hebt nog enkel volgverzoek ontvangen. Wanneer je er eentje ontvangt, valt dat hier te zien.",
   "empty_column.hashtag": "Er is nog niks te vinden onder deze hashtag.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Nieuws",
   "explore.trending_statuses": "Berichten",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Klaar",
   "follow_recommendations.heading": "Volg mensen waarvan je graag berichten wil zien! Hier zijn enkele aanbevelingen.",
   "follow_recommendations.lead": "Berichten van mensen die je volgt zullen in chronologische volgorde onder start verschijnen. Wees niet bang om hierin fouten te maken, want je kunt mensen op elk moment net zo eenvoudig ontvolgen!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Een van deze",
   "hashtag.column_settings.tag_mode.none": "Geen van deze",
   "hashtag.column_settings.tag_toggle": "Additionele tags aan deze kolom toevoegen",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Hashtag volgen",
   "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Hashtag ontvolgen",
   "home.column_settings.basic": "Algemeen",
   "home.column_settings.show_reblogs": "Boosts tonen",
   "home.column_settings.show_replies": "Reacties tonen",
@@ -240,7 +257,7 @@
   "keyboard_shortcuts.direct": "Directe berichten tonen",
   "keyboard_shortcuts.down": "Naar beneden in de lijst bewegen",
   "keyboard_shortcuts.enter": "Volledig bericht tonen",
-  "keyboard_shortcuts.favourite": "Aan jouw favorieten toevoegen",
+  "keyboard_shortcuts.favourite": "Als favoriet markeren",
   "keyboard_shortcuts.favourites": "Favorieten tonen",
   "keyboard_shortcuts.federated": "Globale tijdlijn tonen",
   "keyboard_shortcuts.heading": "Sneltoetsen",
@@ -318,8 +335,8 @@
   "navigation_bar.public_timeline": "Globale tijdlijn",
   "navigation_bar.security": "Beveiliging",
   "notification.admin.report": "{name} heeft {target} geapporteerd",
-  "notification.admin.sign_up": "{name} heeft zich aangemeld",
-  "notification.favourite": "{name} voegde jouw bericht als favoriet toe",
+  "notification.admin.sign_up": "{name} heeft zich geregistreerd",
+  "notification.favourite": "{name} markeerde jouw bericht als favoriet",
   "notification.follow": "{name} volgt jou nu",
   "notification.follow_request": "{name} wil jou graag volgen",
   "notification.mention": "{name} vermeldde jou",
@@ -331,7 +348,7 @@
   "notifications.clear": "Meldingen verwijderen",
   "notifications.clear_confirmation": "Weet je het zeker dat je al jouw meldingen wilt verwijderen?",
   "notifications.column_settings.admin.report": "Nieuwe rapportages:",
-  "notifications.column_settings.admin.sign_up": "Nieuwe aanmeldingen:",
+  "notifications.column_settings.admin.sign_up": "Nieuwe registraties:",
   "notifications.column_settings.alert": "Desktopmeldingen",
   "notifications.column_settings.favourite": "Favorieten:",
   "notifications.column_settings.filter_bar.advanced": "Alle categorieën tonen",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "{count, plural, one {{count} keer} other {{count} keer}} bewerkt",
   "status.embed": "Insluiten",
   "status.favourite": "Favoriet",
+  "status.filter": "Filter this post",
   "status.filtered": "Gefilterd",
   "status.hide": "Bericht verbergen",
   "status.history.created": "{name} plaatste dit {date}",
diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json
index 1a8904cd2..33c06e11e 100644
--- a/app/javascript/mastodon/locales/nn.json
+++ b/app/javascript/mastodon/locales/nn.json
@@ -41,24 +41,25 @@
   "account.statuses_counter": "{count, plural, one {{counter} tut} other {{counter} tut}}",
   "account.unblock": "Slutt å blokera @{name}",
   "account.unblock_domain": "Vis {domain}",
-  "account.unblock_short": "Opphev blokkering",
+  "account.unblock_short": "Avblokker",
   "account.unendorse": "Ikkje framhev på profil",
   "account.unfollow": "Slutt å fylgja",
-  "account.unmute": "Av-demp @{name}",
+  "account.unmute": "Opphev målbinding av @{name}",
   "account.unmute_notifications": "Vis varsel frå @{name}",
-  "account.unmute_short": "Opphev demping",
+  "account.unmute_short": "Opphev målbinding",
   "account_note.placeholder": "Klikk for å leggja til merknad",
   "admin.dashboard.daily_retention": "User retention rate by day after sign-up",
   "admin.dashboard.monthly_retention": "User retention rate by month after sign-up",
   "admin.dashboard.retention.average": "Gjennomsnitt",
   "admin.dashboard.retention.cohort": "Sign-up month",
-  "admin.dashboard.retention.cohort_size": "Nye brukere",
+  "admin.dashboard.retention.cohort_size": "Nye brukarar",
   "alert.rate_limited.message": "Ver venleg å prøva igjen etter {retry_time, time, medium}.",
   "alert.rate_limited.title": "Begrensa rate",
   "alert.unexpected.message": "Eit uventa problem oppstod.",
   "alert.unexpected.title": "Oi sann!",
   "announcement.announcement": "Kunngjering",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} per veke",
   "boost_modal.combo": "Du kan trykkja {combo} for å hoppa over dette neste gong",
   "bundle_column_error.body": "Noko gjekk gale mens denne komponenten vart lasta ned.",
@@ -70,7 +71,7 @@
   "column.blocks": "Blokkerte brukarar",
   "column.bookmarks": "Bokmerke",
   "column.community": "Lokal tidsline",
-  "column.direct": "Direct messages",
+  "column.direct": "Direktemeldingar",
   "column.directory": "Sjå gjennom profilar",
   "column.domain_blocks": "Gøymde domene",
   "column.favourites": "Favorittar",
@@ -92,10 +93,10 @@
   "community.column_settings.local_only": "Berre lokalt",
   "community.column_settings.media_only": "Berre media",
   "community.column_settings.remote_only": "Berre eksternt",
-  "compose.language.change": "Change language",
+  "compose.language.change": "Byt språk",
   "compose.language.search": "Search languages...",
   "compose_form.direct_message_warning_learn_more": "Lær meir",
-  "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.",
+  "compose_form.encryption_warning": "Innlegg på Mastodon er ikkje ende-til-ende-krypterte. Ikkje del eventuell sensitiv informasjon via Mastodon.",
   "compose_form.hashtag_warning": "Dette tutet vert ikkje oppført under nokon emneknagg sidan det ikkje er oppført. Berre offentlege tut kan verta søkt etter med emneknagg.",
   "compose_form.lock_disclaimer": "Kontoen din er ikkje {locked}. Kven som helst kan fylgja deg for å sjå innlegga dine som berre visast til fylgjarar.",
   "compose_form.lock_disclaimer.lock": "låst",
@@ -108,7 +109,7 @@
   "compose_form.poll.switch_to_single": "Endra avstemninga til tillate berre eitt val",
   "compose_form.publish": "Publish",
   "compose_form.publish_loud": "{publish}!",
-  "compose_form.save_changes": "Save changes",
+  "compose_form.save_changes": "Lagre endringar",
   "compose_form.sensitive.hide": "Merk medium som sensitivt",
   "compose_form.sensitive.marked": "Medium er markert som sensitivt",
   "compose_form.sensitive.unmarked": "Medium er ikkje merka som sensitivt",
@@ -124,7 +125,7 @@
   "confirmations.delete_list.confirm": "Slett",
   "confirmations.delete_list.message": "Er du sikker på at du vil sletta denne lista for alltid?",
   "confirmations.discard_edit_media.confirm": "Forkast",
-  "confirmations.discard_edit_media.message": "You have unsaved changes to the media description or preview, discard them anyway?",
+  "confirmations.discard_edit_media.message": "Du har ulagra endringar i mediabeskrivinga eller førehandsvisinga. Vil du forkaste dei likevel?",
   "confirmations.domain_block.confirm": "Gøym heile domenet",
   "confirmations.domain_block.message": "Er du heilt, heilt sikker på at du vil blokkera heile {domain}? I dei fleste tilfelle er det godt nok og føretrekt med nokre få målretta blokkeringar eller målbindingar. Du kjem ikkje til å sjå innhald frå det domenet i nokon fødererte tidsliner eller i varsla dine. Fylgjarane dine frå det domenet vert fjerna.",
   "confirmations.logout.confirm": "Logg ut",
@@ -178,7 +179,7 @@
   "empty_column.follow_requests": "Du har ingen følgjeførespurnadar ennå. Når du får ein, så vil den dukke opp her.",
   "empty_column.hashtag": "Det er ingenting i denne emneknaggen ennå.",
   "empty_column.home": "Heime-tidslinja di er tom! Besøk {public} eller søk for å starte og å møte andre brukarar.",
-  "empty_column.home.suggestions": "Se noen forslag",
+  "empty_column.home.suggestions": "Sjå nokre forslag",
   "empty_column.list": "Det er ingenting i denne lista enno. Når medlemer av denne lista legg ut nye statusar, så dukkar dei opp her.",
   "empty_column.lists": "Du har ingen lister enno. Når du lagar ei, så dukkar ho opp her.",
   "empty_column.mutes": "Du har ikkje målbunde nokon brukarar enno.",
@@ -190,14 +191,30 @@
   "error.unexpected_crash.next_steps_addons": "Prøv å deaktivere dem og laste siden på nytt. Hvis det ikke hjelper, kan du fremdeles bruke Mastodon via en annen nettleser eller en annen app.",
   "errors.unexpected_crash.copy_stacktrace": "Kopier stacktrace til utklippstavla",
   "errors.unexpected_crash.report_issue": "Rapporter problem",
-  "explore.search_results": "Søkeresultater",
+  "explore.search_results": "Søkeresultat",
   "explore.suggested_follows": "For deg",
   "explore.title": "Utforsk",
-  "explore.trending_links": "Nyheter",
+  "explore.trending_links": "Nyheiter",
   "explore.trending_statuses": "Innlegg",
-  "explore.trending_tags": "Hashtags",
+  "explore.trending_tags": "Emneknaggar",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Ferdig",
-  "follow_recommendations.heading": "Følg folk du ønsker å se innlegg fra! Her er noen forslag.",
+  "follow_recommendations.heading": "Fylg folk du ønsker å sjå innlegg frå! Her er nokre forslag.",
   "follow_recommendations.lead": "Innlegg fra mennesker du følger vil vises i kronologisk rekkefølge på hjemmefeed. Ikke vær redd for å gjøre feil, du kan slutte å følge folk like enkelt som alt!",
   "follow_request.authorize": "Autoriser",
   "follow_request.reject": "Avvis",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Kva som helst av desse",
   "hashtag.column_settings.tag_mode.none": "Ikkje nokon av disse",
   "hashtag.column_settings.tag_toggle": "Inkluder ekstra emneknaggar for denne kolonna",
-  "hashtag.follow": "Follow hashtag",
-  "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.follow": "Fylg emneknagg",
+  "hashtag.total_volume": "Totalt volum siste {days, plural, one {dag} other {{days} dagar}}",
+  "hashtag.unfollow": "Slutt å fylgje emneknaggen",
   "home.column_settings.basic": "Enkelt",
   "home.column_settings.show_reblogs": "Vis framhevingar",
   "home.column_settings.show_replies": "Vis svar",
@@ -270,8 +287,8 @@
   "lightbox.expand": "Ekspander bildevisning boks",
   "lightbox.next": "Neste",
   "lightbox.previous": "Førre",
-  "limited_account_hint.action": "Show profile anyway",
-  "limited_account_hint.title": "This profile has been hidden by the moderators of your server.",
+  "limited_account_hint.action": "Vis profilen likevel",
+  "limited_account_hint.title": "Denne profilen har vorte skjult av moderatorane på tenaren din.",
   "lists.account.add": "Legg til i liste",
   "lists.account.remove": "Fjern frå liste",
   "lists.delete": "Slett liste",
@@ -280,7 +297,7 @@
   "lists.new.create": "Legg til liste",
   "lists.new.title_placeholder": "Ny listetittel",
   "lists.replies_policy.followed": "Enhver fulgt bruker",
-  "lists.replies_policy.list": "Medlemmer i listen",
+  "lists.replies_policy.list": "Medlem i lista",
   "lists.replies_policy.none": "Ikkje nokon",
   "lists.replies_policy.title": "Vis svar på:",
   "lists.search": "Søk gjennom folk du følgjer",
@@ -298,7 +315,7 @@
   "navigation_bar.bookmarks": "Bokmerke",
   "navigation_bar.community_timeline": "Lokal tidsline",
   "navigation_bar.compose": "Lag eit nytt tut",
-  "navigation_bar.direct": "Direct messages",
+  "navigation_bar.direct": "Direktemeldingar",
   "navigation_bar.discover": "Oppdag",
   "navigation_bar.domain_blocks": "Skjulte domene",
   "navigation_bar.edit_profile": "Rediger profil",
@@ -317,7 +334,7 @@
   "navigation_bar.preferences": "Innstillingar",
   "navigation_bar.public_timeline": "Føderert tidsline",
   "navigation_bar.security": "Tryggleik",
-  "notification.admin.report": "{name} reported {target}",
+  "notification.admin.report": "{name} rapporterte {target}",
   "notification.admin.sign_up": "{name} signed up",
   "notification.favourite": "{name} merkte statusen din som favoritt",
   "notification.follow": "{name} fylgde deg",
@@ -327,10 +344,10 @@
   "notification.poll": "Ei rundspørjing du har røysta i er ferdig",
   "notification.reblog": "{name} framheva statusen din",
   "notification.status": "{name} la nettopp ut",
-  "notification.update": "{name} edited a post",
+  "notification.update": "{name} redigerte eit innlegg",
   "notifications.clear": "Tøm varsel",
   "notifications.clear_confirmation": "Er du sikker på at du vil fjerna alle varsla dine for alltid?",
-  "notifications.column_settings.admin.report": "New reports:",
+  "notifications.column_settings.admin.report": "Nye rapportar:",
   "notifications.column_settings.admin.sign_up": "New sign-ups:",
   "notifications.column_settings.alert": "Skrivebordsvarsel",
   "notifications.column_settings.favourite": "Favorittar:",
@@ -346,9 +363,9 @@
   "notifications.column_settings.show": "Vis i kolonne",
   "notifications.column_settings.sound": "Spel av lyd",
   "notifications.column_settings.status": "Nye tuter:",
-  "notifications.column_settings.unread_notifications.category": "Unread notifications",
-  "notifications.column_settings.unread_notifications.highlight": "Highlight unread notifications",
-  "notifications.column_settings.update": "Redigeringer:",
+  "notifications.column_settings.unread_notifications.category": "Uleste varsel",
+  "notifications.column_settings.unread_notifications.highlight": "Marker uleste varsel",
+  "notifications.column_settings.update": "Redigeringar:",
   "notifications.filter.all": "Alle",
   "notifications.filter.boosts": "Framhevingar",
   "notifications.filter.favourites": "Favorittar",
@@ -372,15 +389,15 @@
   "poll.total_votes": "{count, plural, one {# røyst} other {# røyster}}",
   "poll.vote": "Røyst",
   "poll.voted": "Du røysta på dette svaret",
-  "poll.votes": "{votes, plural, one {# vote} other {# votes}}",
+  "poll.votes": "{votes, plural, one {# stemme} other {# stemmer}}",
   "poll_button.add_poll": "Start ei meiningsmåling",
   "poll_button.remove_poll": "Fjern røyst",
   "privacy.change": "Juster status-synlegheit",
   "privacy.direct.long": "Legg berre ut for nemnde brukarar",
-  "privacy.direct.short": "Direct",
+  "privacy.direct.short": "Kun nemnde personar",
   "privacy.private.long": "Post kun til følgjarar",
-  "privacy.private.short": "Followers-only",
-  "privacy.public.long": "Visible for all",
+  "privacy.private.short": "Kun fylgjarar",
+  "privacy.public.long": "Synleg for alle",
   "privacy.public.short": "Offentleg",
   "privacy.unlisted.long": "Visible for all, but opted-out of discovery features",
   "privacy.unlisted.short": "Uoppført",
@@ -388,11 +405,11 @@
   "regeneration_indicator.label": "Lastar…",
   "regeneration_indicator.sublabel": "Heimetidslinja di vert førebudd!",
   "relative_time.days": "{number}dg",
-  "relative_time.full.days": "{number, plural, one {# day} other {# days}} ago",
-  "relative_time.full.hours": "{number, plural, one {# hour} other {# hours}} ago",
-  "relative_time.full.just_now": "just now",
-  "relative_time.full.minutes": "{number, plural, one {# minute} other {# minutes}} ago",
-  "relative_time.full.seconds": "{number, plural, one {# second} other {# seconds}} ago",
+  "relative_time.full.days": "{number, plural, one {# dag} other {# dagar}} sidan",
+  "relative_time.full.hours": "{number, plural, one {# time} other {# timar}} sidan",
+  "relative_time.full.just_now": "nettopp nå",
+  "relative_time.full.minutes": "{number, plural, one {# minutt} other {# minutt}} sidan",
+  "relative_time.full.seconds": "{number, plural, one {# sekund} other {# sekund}} sidan",
   "relative_time.hours": "{number}t",
   "relative_time.just_now": "nå",
   "relative_time.minutes": "{number}min",
@@ -400,46 +417,46 @@
   "relative_time.today": "i dag",
   "reply_indicator.cancel": "Avbryt",
   "report.block": "Blokker",
-  "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.",
-  "report.categories.other": "Other",
+  "report.block_explanation": "Du vil ikkje kunne sjå innlegga deira. Dei vil ikkje kunne sjå innlegga dine eller fylgje deg. Dei kan sjå at dei er blokkert.",
+  "report.categories.other": "Anna",
   "report.categories.spam": "Søppelpost",
-  "report.categories.violation": "Content violates one or more server rules",
-  "report.category.subtitle": "Choose the best match",
-  "report.category.title": "Tell us what's going on with this {type}",
+  "report.categories.violation": "Innhaldet bryt ei eller fleire regler for tenaren",
+  "report.category.subtitle": "Vel det som passar best",
+  "report.category.title": "Fortel oss kva som skjer med denne {type}",
   "report.category.title_account": "profil",
   "report.category.title_status": "innlegg",
-  "report.close": "Utført",
-  "report.comment.title": "Is there anything else you think we should know?",
+  "report.close": "Ferdig",
+  "report.comment.title": "Er det noko anna du meiner me bør vite?",
   "report.forward": "Vidaresend til {target}",
   "report.forward_hint": "Kontoen er frå ein annan tenar. Vil du senda ein anonymisert kopi av rapporten dit òg?",
-  "report.mute": "Demp",
+  "report.mute": "Målbind",
   "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.",
   "report.next": "Neste",
   "report.placeholder": "Tilleggskommentarar",
-  "report.reasons.dislike": "Jeg liker det ikke",
-  "report.reasons.dislike_description": "It is not something you want to see",
-  "report.reasons.other": "It's something else",
-  "report.reasons.other_description": "The issue does not fit into other categories",
-  "report.reasons.spam": "Det er spam",
-  "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies",
-  "report.reasons.violation": "It violates server rules",
-  "report.reasons.violation_description": "You are aware that it breaks specific rules",
+  "report.reasons.dislike": "Eg likar det ikkje",
+  "report.reasons.dislike_description": "Det er ikkje noko du ønsker å sjå",
+  "report.reasons.other": "Det er noko anna",
+  "report.reasons.other_description": "Problemet passar ikkje inn i dei andre kategoriane",
+  "report.reasons.spam": "Det er søppelpost",
+  "report.reasons.spam_description": "Skadelege lenker, falskt engasjement og gjentakande svar",
+  "report.reasons.violation": "Det bryt tenaren sine reglar",
+  "report.reasons.violation_description": "Du veit at den bryt spesifikke reglar",
   "report.rules.subtitle": "Select all that apply",
-  "report.rules.title": "Which rules are being violated?",
+  "report.rules.title": "Kva reglar vert brotne?",
   "report.statuses.subtitle": "Select all that apply",
   "report.statuses.title": "Are there any posts that back up this report?",
   "report.submit": "Send inn",
   "report.target": "Rapporterer {target}",
   "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:",
   "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:",
-  "report.thanks.title": "Don't want to see this?",
-  "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.",
+  "report.thanks.title": "Vil du ikkje sjå dette?",
+  "report.thanks.title_actionable": "Takk for at du rapporterer, me skal sjå på dette.",
   "report.unfollow": "Unfollow @{name}",
   "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.",
-  "report_notification.attached_statuses": "{count, plural, one {{count} post} other {{count} posts}} attached",
-  "report_notification.categories.other": "Other",
-  "report_notification.categories.spam": "Spam",
-  "report_notification.categories.violation": "Rule violation",
+  "report_notification.attached_statuses": "{count, plural, one {{count} innlegg} other {{count} innlegg}} lagt ved",
+  "report_notification.categories.other": "Anna",
+  "report_notification.categories.spam": "Søppelpost",
+  "report_notification.categories.violation": "Regelbrot",
   "report_notification.open": "Open report",
   "search.placeholder": "Søk",
   "search_popout.search_format": "Avansert søkeformat",
@@ -451,7 +468,7 @@
   "search_results.accounts": "Folk",
   "search_results.all": "All",
   "search_results.hashtags": "Emneknaggar",
-  "search_results.nothing_found": "Could not find anything for these search terms",
+  "search_results.nothing_found": "Kunne ikkje finne noko for desse søkeorda",
   "search_results.statuses": "Tut",
   "search_results.statuses_fts_disabled": "På denne Matsodon-tenaren kan du ikkje søkja på tut etter innhaldet deira.",
   "search_results.total": "{count, number} {count, plural, one {treff} other {treff}}",
@@ -465,15 +482,16 @@
   "status.delete": "Slett",
   "status.detailed_status": "Detaljert samtalevisning",
   "status.direct": "Send melding til @{name}",
-  "status.edit": "Edit",
-  "status.edited": "Edited {date}",
-  "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
+  "status.edit": "Rediger",
+  "status.edited": "Redigert {date}",
+  "status.edited_x_times": "Redigert {count, plural, one {{count} gong} other {{count} gonger}}",
   "status.embed": "Bygg inn",
   "status.favourite": "Favoritt",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrert",
-  "status.hide": "Hide toot",
-  "status.history.created": "{name} created {date}",
-  "status.history.edited": "{name} edited {date}",
+  "status.hide": "Gøym innlegg",
+  "status.history.created": "{name} oppretta {date}",
+  "status.history.edited": "{name} redigerte {date}",
   "status.load_more": "Last inn meir",
   "status.media_hidden": "Medium gøymd",
   "status.mention": "Nemn @{name}",
@@ -495,7 +513,7 @@
   "status.report": "Rapporter @{name}",
   "status.sensitive_warning": "Sensitivt innhald",
   "status.share": "Del",
-  "status.show_filter_reason": "Show anyway",
+  "status.show_filter_reason": "Vis likevel",
   "status.show_less": "Vis mindre",
   "status.show_less_all": "Vis mindre for alle",
   "status.show_more": "Vis meir",
@@ -532,7 +550,7 @@
   "upload_error.poll": "Filopplasting ikkje tillate med meiningsmålingar.",
   "upload_form.audio_description": "Grei ut for folk med nedsett høyrsel",
   "upload_form.description": "Skildr for synshemja",
-  "upload_form.description_missing": "Ingen beskrivelse lagt til",
+  "upload_form.description_missing": "Inga beskriving er lagt til",
   "upload_form.edit": "Rediger",
   "upload_form.thumbnail": "Bytt miniatyrbilete",
   "upload_form.undo": "Slett",
diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json
index 829be51a5..6e2783713 100644
--- a/app/javascript/mastodon/locales/no.json
+++ b/app/javascript/mastodon/locales/no.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oi!",
   "announcement.announcement": "Kunngjøring",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} per uke",
   "boost_modal.combo": "You kan trykke {combo} for å hoppe over dette neste gang",
   "bundle_column_error.body": "Noe gikk galt mens denne komponenten lastet.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Nyheter",
   "explore.trending_statuses": "Innlegg",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Utført",
   "follow_recommendations.heading": "Følg folk du ønsker å se innlegg fra! Her er noen forslag.",
   "follow_recommendations.lead": "Innlegg fra mennesker du følger vil vises i kronologisk rekkefølge på hjemmefeed. Ikke vær redd for å gjøre feil, du kan slutte å følge folk like enkelt som alt!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Bygge inn",
   "status.favourite": "Lik",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrert",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index b065b4e8f..fa3ef3967 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ops !",
   "announcement.announcement": "Anóncia",
   "attachments_list.unprocessed": "(pas tractat)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Novèlas",
   "explore.trending_statuses": "Publicacions",
   "explore.trending_tags": "Etiquetas",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Acabat",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Modificat {count, plural, un {{count} còp} other {{count} còps}}",
   "status.embed": "Embarcar",
   "status.favourite": "Apondre als favorits",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrat",
   "status.hide": "Hide toot",
   "status.history.created": "{name} o creèt lo {date}",
diff --git a/app/javascript/mastodon/locales/pa.json b/app/javascript/mastodon/locales/pa.json
index 99fdcfd45..c77444bff 100644
--- a/app/javascript/mastodon/locales/pa.json
+++ b/app/javascript/mastodon/locales/pa.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index df7b5cb0d..9550b5b7f 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "O nie!",
   "announcement.announcement": "Ogłoszenie",
   "attachments_list.unprocessed": "(nieprzetworzone)",
+  "audio.hide": "Ukryj dźwięk",
   "autosuggest_hashtag.per_week": "{count} co tydzień",
   "boost_modal.combo": "Naciśnij {combo}, aby pominąć to następnym razem",
   "bundle_column_error.body": "Coś poszło nie tak podczas ładowania tego składnika.",
@@ -200,6 +201,22 @@
   "explore.trending_links": "Aktualności",
   "explore.trending_statuses": "Posty",
   "explore.trending_tags": "Hasztagi",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Gotowe",
   "follow_recommendations.heading": "Śledź ludzi, których wpisy chcesz czytać. Oto kilka propozycji.",
   "follow_recommendations.lead": "Wpisy osób, które śledzisz będą pojawiać się w porządku chronologicznym na stronie głównej. Nie bój się popełniać błędów, możesz bez problemu przestać śledzić każdego w każdej chwili!",
@@ -224,9 +241,9 @@
   "hashtag.column_settings.tag_mode.any": "Dowolne",
   "hashtag.column_settings.tag_mode.none": "Żadne",
   "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Obserwuj hasztag",
   "hashtag.total_volume": "Całkowity wolumen w ciągu {days, plural, one {ostatniego dnia} other {ostatnich {days} dni}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Przestań obserwować hashtag",
   "home.column_settings.basic": "Podstawowe",
   "home.column_settings.show_reblogs": "Pokazuj podbicia",
   "home.column_settings.show_replies": "Pokazuj odpowiedzi",
@@ -475,6 +492,7 @@
   "status.edited_x_times": "Edytowano {count, plural, one {{count} raz} other {{count} razy}}",
   "status.embed": "Osadź",
   "status.favourite": "Dodaj do ulubionych",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrowany(-a)",
   "status.hide": "Schowaj toota",
   "status.history.created": "{name} utworzył(a) {date}",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index 268b100d7..395ef4b86 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Eita!",
   "announcement.announcement": "Comunicados",
   "attachments_list.unprocessed": "(não processado)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} por semana",
   "boost_modal.combo": "Pressione {combo} para pular isso na próxima vez",
   "bundle_column_error.body": "Erro ao carregar este componente.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Notícias",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Salvar",
   "follow_recommendations.heading": "Siga pessoas que você gostaria de acompanhar! Aqui estão algumas sugestões.",
   "follow_recommendations.lead": "Toots de pessoas que você segue aparecerão em ordem cronológica na página inicial. Não tenha medo de cometer erros, você pode facilmente deixar de seguir a qualquer momento!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Editado {count, plural, one {{count} hora} other {{count} vezes}}",
   "status.embed": "Incorporar",
   "status.favourite": "Favoritar",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrado",
   "status.hide": "Hide toot",
   "status.history.created": "{name} criou {date}",
diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json
index 643ef1c6e..ef097b380 100644
--- a/app/javascript/mastodon/locales/pt-PT.json
+++ b/app/javascript/mastodon/locales/pt-PT.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Bolas!",
   "announcement.announcement": "Anúncio",
   "attachments_list.unprocessed": "(não processado)",
+  "audio.hide": "Ocultar áudio",
   "autosuggest_hashtag.per_week": "{count} por semana",
   "boost_modal.combo": "Pode clicar {combo} para não voltar a ver",
   "bundle_column_error.body": "Algo de errado aconteceu enquanto este componente era carregado.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Notícias",
   "explore.trending_statuses": "Publicações",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Concluído",
   "follow_recommendations.heading": "Siga pessoas das quais gostaria de ver publicações! Aqui estão algumas sugestões.",
   "follow_recommendations.lead": "As publicações das pessoas que segue serão exibidos em ordem cronológica na sua página inicial. Não tenha medo de cometer erros, você pode deixar de seguir as pessoas tão facilmente a qualquer momento!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Qualquer destes",
   "hashtag.column_settings.tag_mode.none": "Nenhum destes",
   "hashtag.column_settings.tag_toggle": "Incluir etiquetas adicionais para esta coluna",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Seguir hashtag",
   "hashtag.total_volume": "Volume total {days, plural, one {no último dia} other {nos últimos {days} dias}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Parar de seguir hashtag",
   "home.column_settings.basic": "Básico",
   "home.column_settings.show_reblogs": "Mostrar boosts",
   "home.column_settings.show_replies": "Mostrar respostas",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Editado {count, plural,one {{count} vez} other {{count} vezes}}",
   "status.embed": "Incorporar",
   "status.favourite": "Adicionar aos favoritos",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrada",
   "status.hide": "Esconder publicação",
   "status.history.created": "{name} criado em {date}",
diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json
index a3188f553..ff5ec9b2a 100644
--- a/app/javascript/mastodon/locales/ro.json
+++ b/app/javascript/mastodon/locales/ro.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ups!",
   "announcement.announcement": "Anunț",
   "attachments_list.unprocessed": "(neprocesate)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} pe săptămână",
   "boost_modal.combo": "Poți apăsa {combo} pentru a sări peste asta data viitoare",
   "bundle_column_error.body": "A apărut o eroare la încărcarea acestui element.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Terminat",
   "follow_recommendations.heading": "Urmărește persoanele ale căror postări te-ar interesa! Iată câteva sugestii.",
   "follow_recommendations.lead": "Postările de la persoanele la care te-ai abonat vor apărea în ordine cronologică în cronologia principală. Nu-ți fie teamă să faci greșeli, poți să te dezabonezi oricând de la ei la fel de ușor!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Înglobează",
   "status.favourite": "Favorite",
+  "status.filter": "Filter this post",
   "status.filtered": "Sortate",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 30268a41d..9a03a9ef7 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Упс!",
   "announcement.announcement": "Объявление",
   "attachments_list.unprocessed": "(не обработан)",
+  "audio.hide": "Скрыть аудио",
   "autosuggest_hashtag.per_week": "{count} / неделю",
   "boost_modal.combo": "{combo}, чтобы пропустить это в следующий раз",
   "bundle_column_error.body": "Что-то пошло не так при загрузке этого компонента.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Новости",
   "explore.trending_statuses": "Посты",
   "explore.trending_tags": "Хэштеги",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Готово",
   "follow_recommendations.heading": "Подпишитесь на людей, чьи посты вы бы хотели видеть. Вот несколько предложений.",
   "follow_recommendations.lead": "Посты от людей, на которых вы подписаны, будут отображаться в вашей домашней ленте в хронологическом порядке. Не бойтесь ошибиться — вы так же легко сможете отписаться от них в любое время!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Любой из списка",
   "hashtag.column_settings.tag_mode.none": "Ни один из списка",
   "hashtag.column_settings.tag_toggle": "Включить дополнительные теги для этой колонки",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Подписаться на новые посты",
   "hashtag.total_volume": "Общий объем за {days, plural, =1 {последний день} one {последний {days} день} few {последних {days} дня} many {последних {days} дней} other {последних {days} дней}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Отписаться",
   "home.column_settings.basic": "Основные",
   "home.column_settings.show_reblogs": "Показывать продвижения",
   "home.column_settings.show_replies": "Показывать ответы",
@@ -470,10 +487,11 @@
   "status.edited_x_times": "{count, plural, one {{count} изменение} many {{count} изменений} other {{count} изменения}}",
   "status.embed": "Встроить на свой сайт",
   "status.favourite": "В избранное",
+  "status.filter": "Filter this post",
   "status.filtered": "Отфильтровано",
   "status.hide": "Скрыть пост",
   "status.history.created": "{name} создал {date}",
-  "status.history.edited": "{name} отредактировал {date}",
+  "status.history.edited": "{name} отредактировал(а) {date}",
   "status.load_more": "Загрузить остальное",
   "status.media_hidden": "Файл скрыт",
   "status.mention": "Упомянуть @{name}",
diff --git a/app/javascript/mastodon/locales/sa.json b/app/javascript/mastodon/locales/sa.json
index ecbdf816c..2ebda63cd 100644
--- a/app/javascript/mastodon/locales/sa.json
+++ b/app/javascript/mastodon/locales/sa.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "अरे !",
   "announcement.announcement": "उद्घोषणा",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} प्रतिसप्ताहे",
   "boost_modal.combo": "{combo} अत्र स्प्रष्टुं शक्यते, त्यक्तुमेतमन्यस्मिन् समये",
   "bundle_column_error.body": "विषयस्याऽऽरोपणे कश्चिद्दोषो जातः",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/sc.json b/app/javascript/mastodon/locales/sc.json
index aaecfd8e1..7482d15fe 100644
--- a/app/javascript/mastodon/locales/sc.json
+++ b/app/javascript/mastodon/locales/sc.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oh!",
   "announcement.announcement": "Annùntziu",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} a sa chida",
   "boost_modal.combo": "Podes incarcare {combo} pro brincare custu sa borta chi benit",
   "bundle_column_error.body": "Faddina in su carrigamentu de custu cumponente.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Fatu",
   "follow_recommendations.heading": "Sighi gente de chie boles bìdere is publicatziones! Càstia custos cussìgios.",
   "follow_recommendations.lead": "Is messàgios de gente a sa chi ses sighende ant a èssere ammustrados in òrdine cronològicu in sa lìnia de tempus printzipale tua. Non timas de fàghere errores, acabbare de sighire gente est fàtzile in cale si siat momentu!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Afissa",
   "status.favourite": "Preferidos",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtradu",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/si.json b/app/javascript/mastodon/locales/si.json
index e50ea9135..170c34b57 100644
--- a/app/javascript/mastodon/locales/si.json
+++ b/app/javascript/mastodon/locales/si.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "අපොයි!",
   "announcement.announcement": "නිවේදනය",
   "attachments_list.unprocessed": "(සැකසුම් නොකළ)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "සතියකට {count}",
   "boost_modal.combo": "ඊළඟ වතාවේ මෙය මඟ හැරීමට ඔබට {combo} එබිය හැක",
   "bundle_column_error.body": "මෙම සංරචකය පූරණය කිරීමේදී යම් දෙයක් වැරදී ඇත.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "පුවත්",
   "explore.trending_statuses": "තනතුරු",
   "explore.trending_tags": "හැෂ් ටැග්",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "කළා",
   "follow_recommendations.heading": "ඔබ පළ කිරීම් බැලීමට කැමති පුද්ගලයින් අනුගමනය කරන්න! මෙන්න යෝජනා කිහිපයක්.",
   "follow_recommendations.lead": "ඔබ අනුගමන කරන පුද්ගලයින්ගේ පළ කිරීම් ඔබගේ නිවසේ සංග්‍රහයේ කාලානුක්‍රමික අනුපිළිවෙලට පෙන්වනු ඇත. වැරදි කිරීමට බිය නොවන්න, ඔබට ඕනෑම වේලාවක පහසුවෙන් මිනිසුන් අනුගමනය කළ නොහැක!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "සංස්කරණය කළා {count, plural, one {{count} කාලය} other {{count} වාර}}",
   "status.embed": "එබ්බවූ",
   "status.favourite": "ප්‍රියතම",
+  "status.filter": "Filter this post",
   "status.filtered": "පෙරන ලද",
   "status.hide": "Hide toot",
   "status.history.created": "{name} නිර්මාණය {date}",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index 3454fe7d2..8aeb2aec6 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ups!",
   "announcement.announcement": "Oboznámenie",
   "attachments_list.unprocessed": "(nespracované)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} týždenne",
   "boost_modal.combo": "Nabudúce môžeš kliknúť {combo} pre preskočenie",
   "bundle_column_error.body": "Pri načítaní tohto prvku nastala nejaká chyba.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Novinky",
   "explore.trending_statuses": "Príspevky",
   "explore.trending_tags": "Haštagy",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Hotovo",
   "follow_recommendations.heading": "Následuj ľudí od ktorých by si chcel/a vidieť príspevky! Tu sú nejaké návrhy.",
   "follow_recommendations.lead": "Príspevky od ľudi ktorých sledujete sa zobrazia v chronologickom poradí na Vašej nástenke. Nebojte sa spraviť chyby, vždy môžete zrušiť sledovanie konkrétnych ľudí!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Hociktorý z týchto",
   "hashtag.column_settings.tag_mode.none": "Žiaden z týchto",
   "hashtag.column_settings.tag_toggle": "Vlož dodatočné haštagy pre tento stĺpec",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Nasleduj haštag",
   "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Nesleduj haštag",
   "home.column_settings.basic": "Základné",
   "home.column_settings.show_reblogs": "Ukáž vyzdvihnuté",
   "home.column_settings.show_replies": "Ukáž odpovede",
@@ -401,7 +418,7 @@
   "reply_indicator.cancel": "Zrušiť",
   "report.block": "Blokuj",
   "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.",
-  "report.categories.other": "Other",
+  "report.categories.other": "Ostatné",
   "report.categories.spam": "Spam",
   "report.categories.violation": "Content violates one or more server rules",
   "report.category.subtitle": "Choose the best match",
@@ -437,7 +454,7 @@
   "report.unfollow": "Nesleduj @{name}",
   "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.",
   "report_notification.attached_statuses": "{count, plural, one {{count} post} other {{count} posts}} attached",
-  "report_notification.categories.other": "Other",
+  "report_notification.categories.other": "Ostatné",
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Rule violation",
   "report_notification.open": "Open report",
@@ -470,8 +487,9 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Vložiť",
   "status.favourite": "Páči sa mi",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrované",
-  "status.hide": "Hide toot",
+  "status.hide": "Skry príspevok",
   "status.history.created": "{name} vytvoril/a {date}",
   "status.history.edited": "{name} upravil/a {date}",
   "status.load_more": "Ukáž viac",
@@ -495,7 +513,7 @@
   "status.report": "Nahlás @{name}",
   "status.sensitive_warning": "Chúlostivý obsah",
   "status.share": "Zdieľaj",
-  "status.show_filter_reason": "Show anyway",
+  "status.show_filter_reason": "Ukáž aj tak",
   "status.show_less": "Zobraz menej",
   "status.show_less_all": "Všetkým ukáž menej",
   "status.show_more": "Ukáž viac",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index 733614f3e..c793d9de8 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Uups!",
   "announcement.announcement": "Objava",
   "attachments_list.unprocessed": "(neobdelano)",
+  "audio.hide": "Skrij zvok",
   "autosuggest_hashtag.per_week": "{count} na teden",
   "boost_modal.combo": "Če želite preskočiti to, lahko pritisnete {combo}",
   "bundle_column_error.body": "Med nalaganjem te komponente je prišlo do napake.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Novice",
   "explore.trending_statuses": "Objave",
   "explore.trending_tags": "Ključniki",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Opravljeno",
   "follow_recommendations.heading": "Sledite osebam, katerih objave želite videti! Tukaj je nekaj predlogov.",
   "follow_recommendations.lead": "Objave oseb, ki jim sledite, se bodo prikazale v kronološkem zaporedju v vašem domačem viru. Ne bojte se storiti napake, osebam enako enostavno nehate slediti kadar koli!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Karkoli od naštetega",
   "hashtag.column_settings.tag_mode.none": "Nič od naštetega",
   "hashtag.column_settings.tag_toggle": "Za ta stolpec vključi dodatne oznake",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Sledi ključniku",
   "hashtag.total_volume": "Skupen obseg v {days, plural, one {zadnjem {day} dnevu} two {zadnjih {days} dneh} few {zadnjih {days} dneh} other {zadnjih {days} dneh}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Nehaj slediti ključniku",
   "home.column_settings.basic": "Osnovno",
   "home.column_settings.show_reblogs": "Pokaži izpostavitve",
   "home.column_settings.show_replies": "Pokaži odgovore",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Urejeno {count, plural, one {#-krat} two {#-krat} few {#-krat} other {#-krat}}",
   "status.embed": "Vgradi",
   "status.favourite": "Priljubljen",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrirano",
   "status.hide": "Skrij tut",
   "status.history.created": "{name}: ustvarjeno {date}",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index 8bc440503..0b7fabb45 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Hëm!",
   "announcement.announcement": "Lajmërim",
   "attachments_list.unprocessed": "(e papërpunuar)",
+  "audio.hide": "Fshihe audion",
   "autosuggest_hashtag.per_week": "{count} për javë",
   "boost_modal.combo": "Që kjo të anashkalohet herës tjetër, mund të shtypni {combo}",
   "bundle_column_error.body": "Diç shkoi ters teksa ngarkohej ky përbërës.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Lajme",
   "explore.trending_statuses": "Postime",
   "explore.trending_tags": "Hashtagë",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "U bë",
   "follow_recommendations.heading": "Ndiqni persona prej të cilëve doni të shihni postime! Ja ca sugjerime.",
   "follow_recommendations.lead": "Postimet prej personash që ndiqni do të shfaqen në rend kohor te prurja juaj kryesore. Mos kini frikë të bëni gabime, mund të ndalni po aq kollaj ndjekjen e dikujt, në çfarëdo kohe!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Cilindo prej këtyre",
   "hashtag.column_settings.tag_mode.none": "Asnjë prej këtyre",
   "hashtag.column_settings.tag_toggle": "Përfshi etiketa shtesë për këtë shtyllë",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Ndiqe hashtag-un",
   "hashtag.total_volume": "Vëllim gjithsej {days, plural, një {day} other {{days} ditët}} e fundit",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Hiqe ndjekjen e hashtag-ut",
   "home.column_settings.basic": "Bazë",
   "home.column_settings.show_reblogs": "Shfaq përforcime",
   "home.column_settings.show_replies": "Shfaq përgjigje",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Përpunuar {count, plural, one {{count} herë} other {{count} herë}}",
   "status.embed": "Trupëzim",
   "status.favourite": "I parapëlqyer",
+  "status.filter": "Filter this post",
   "status.filtered": "I filtruar",
   "status.hide": "Fshihe mesazhin",
   "status.history.created": "{name} u krijua më {date}",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index 131af97e1..8e955727d 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} per week",
   "boost_modal.combo": "Možete pritisnuti {combo} da preskočite ovo sledeći put",
   "bundle_column_error.body": "Nešto je pošlo po zlu prilikom učitavanja ove komponente.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Ugradi na sajt",
   "status.favourite": "Omiljeno",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index a2409e957..442e7ee3d 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Упс!",
   "announcement.announcement": "Најава",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} недељно",
   "boost_modal.combo": "Можете притиснути {combo} да прескочите ово следећи пут",
   "bundle_column_error.body": "Нешто је пошло по злу приликом учитавања ове компоненте.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Угради на сајт",
   "status.favourite": "Омиљено",
+  "status.filter": "Filter this post",
   "status.filtered": "Филтрирано",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 9cc1c326a..7fb445b9e 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Hoppsan!",
   "announcement.announcement": "Meddelande",
   "attachments_list.unprocessed": "(obearbetad)",
+  "audio.hide": "Dölj audio",
   "autosuggest_hashtag.per_week": "{count} per vecka",
   "boost_modal.combo": "Du kan trycka {combo} för att slippa detta nästa gång",
   "bundle_column_error.body": "Något gick fel medan denna komponent laddades.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Nyheter",
   "explore.trending_statuses": "Inlägg",
   "explore.trending_tags": "Hashtaggar",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Klar",
   "follow_recommendations.heading": "Följ personer som du skulle vilja se inlägg från! Här finns det några förslag.",
   "follow_recommendations.lead": "Inlägg från personer du följer kommer att dyka upp i kronologisk ordning i ditt hem-flöde. Var inte rädd för att göra misstag, du kan sluta följa människor lika enkelt när som helst!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Redigerad {count, plural, one {{count} gång} other {{count} gånger}}",
   "status.embed": "Bädda in",
   "status.favourite": "Favorit",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrerat",
   "status.hide": "Hide toot",
   "status.history.created": "{name} skapade {date}",
diff --git a/app/javascript/mastodon/locales/szl.json b/app/javascript/mastodon/locales/szl.json
index 99fdcfd45..c77444bff 100644
--- a/app/javascript/mastodon/locales/szl.json
+++ b/app/javascript/mastodon/locales/szl.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json
index cc7241bad..728cfac11 100644
--- a/app/javascript/mastodon/locales/ta.json
+++ b/app/javascript/mastodon/locales/ta.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "அச்சச்சோ!",
   "announcement.announcement": "அறிவிப்பு",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "ஒவ்வொரு வாரம் {count}",
   "boost_modal.combo": "நீங்கள் இதை அடுத்தமுறை தவிர்க்க {combo} வை அழுத்தவும்",
   "bundle_column_error.body": "இக்கூற்றை ஏற்றம் செய்யும்பொழுது ஏதோ தவறு ஏற்பட்டுள்ளது.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "கிடத்து",
   "status.favourite": "விருப்பத்துக்குகந்த",
+  "status.filter": "Filter this post",
   "status.filtered": "வடிகட்டு",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/tai.json b/app/javascript/mastodon/locales/tai.json
index 17b0e1ed1..beba8e333 100644
--- a/app/javascript/mastodon/locales/tai.json
+++ b/app/javascript/mastodon/locales/tai.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json
index bbe99b4a6..d5cc02b10 100644
--- a/app/javascript/mastodon/locales/te.json
+++ b/app/javascript/mastodon/locales/te.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "అయ్యో!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} per week",
   "boost_modal.combo": "మీరు తదుపరిసారి దీనిని దాటవేయడానికి {combo} నొక్కవచ్చు",
   "bundle_column_error.body": "ఈ భాగం లోడ్ అవుతున్నప్పుడు ఏదో తప్పు జరిగింది.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "ఎంబెడ్",
   "status.favourite": "ఇష్టపడు",
+  "status.filter": "Filter this post",
   "status.filtered": "వడకట్టబడిన",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 0bff3caab..38539d512 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "อุปส์!",
   "announcement.announcement": "ประกาศ",
   "attachments_list.unprocessed": "(ยังไม่ได้ประมวลผล)",
+  "audio.hide": "ซ่อนเสียง",
   "autosuggest_hashtag.per_week": "{count} ต่อสัปดาห์",
   "boost_modal.combo": "คุณสามารถกด {combo} เพื่อข้ามสิ่งนี้ในครั้งถัดไป",
   "bundle_column_error.body": "มีบางอย่างผิดพลาดขณะโหลดส่วนประกอบนี้",
@@ -196,6 +197,22 @@
   "explore.trending_links": "ข่าว",
   "explore.trending_statuses": "โพสต์",
   "explore.trending_tags": "แฮชแท็ก",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "เสร็จสิ้น",
   "follow_recommendations.heading": "ติดตามผู้คนที่คุณต้องการเห็นโพสต์! นี่คือข้อเสนอแนะบางส่วน",
   "follow_recommendations.lead": "โพสต์จากผู้คนที่คุณติดตามจะแสดงตามลำดับเวลาในฟีดหน้าแรกของคุณ อย่ากลัวที่จะทำผิดพลาด คุณสามารถเลิกติดตามผู้คนได้อย่างง่ายดายเมื่อใดก็ตาม!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "ใดก็ตามนี้",
   "hashtag.column_settings.tag_mode.none": "ไม่ใช่ทั้งหมดนี้",
   "hashtag.column_settings.tag_toggle": "รวมแท็กเพิ่มเติมสำหรับคอลัมน์นี้",
-  "hashtag.follow": "Follow hashtag",
-  "hashtag.total_volume": "Total volume in the last {days, plural, one {day} other {{days} days}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.follow": "ติดตามแฮชแท็ก",
+  "hashtag.total_volume": "ปริมาณรวมใน {days, plural, other {{days} วัน}}ที่ผ่านมา",
+  "hashtag.unfollow": "เลิกติดตามแฮชแท็ก",
   "home.column_settings.basic": "พื้นฐาน",
   "home.column_settings.show_reblogs": "แสดงการดัน",
   "home.column_settings.show_replies": "แสดงการตอบกลับ",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "แก้ไข {count, plural, other {{count} ครั้ง}}",
   "status.embed": "ฝัง",
   "status.favourite": "ชื่นชอบ",
+  "status.filter": "Filter this post",
   "status.filtered": "กรองอยู่",
   "status.hide": "ซ่อนโพสต์",
   "status.history.created": "{name} ได้สร้างเมื่อ {date}",
@@ -520,7 +538,7 @@
   "timeline_hint.resources.followers": "ผู้ติดตาม",
   "timeline_hint.resources.follows": "การติดตาม",
   "timeline_hint.resources.statuses": "โพสต์ที่เก่ากว่า",
-  "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
+  "trends.counter_by_accounts": "{count, plural, other {{counter} คน}}ใน {days, plural, other {{days} วัน}}ที่ผ่านมา",
   "trends.trending_now": "กำลังนิยม",
   "ui.beforeunload": "แบบร่างของคุณจะหายไปหากคุณออกจาก Mastodon",
   "units.short.billion": "{count} พันล้าน",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 3948bde5e..35c888e47 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -12,7 +12,7 @@
   "account.disable_notifications": "@{name} kişisinin gönderi bildirimlerini kapat",
   "account.domain_blocked": "Alan adı engellendi",
   "account.edit_profile": "Profili düzenle",
-  "account.enable_notifications": "@{name} kişisinin gönderi bildirimlerini aç",
+  "account.enable_notifications": "@{name}'in gönderilerini bana bildir",
   "account.endorse": "Profilimde öne çıkar",
   "account.follow": "Takip et",
   "account.followers": "Takipçi",
@@ -20,23 +20,23 @@
   "account.followers_counter": "{count, plural, one {{counter} Takipçi} other {{counter} Takipçi}}",
   "account.following": "Takip Ediliyor",
   "account.following_counter": "{count, plural, one {{counter} Takip Edilen} other {{counter} Takip Edilen}}",
-  "account.follows.empty": "Bu kullanıcı henüz kimseyi takip etmiyor.",
+  "account.follows.empty": "Bu kullanıcı henüz hiçkimseyi takip etmiyor.",
   "account.follows_you": "Seni takip ediyor",
   "account.hide_reblogs": "@{name} kişisinin boostlarını gizle",
   "account.joined": "{date} tarihinde katıldı",
   "account.link_verified_on": "Bu bağlantının sahipliği {date} tarihinde kontrol edildi",
   "account.locked_info": "Bu hesabın gizlilik durumu gizli olarak ayarlanmış. Sahibi, onu kimin takip edebileceğini manuel olarak onaylıyor.",
   "account.media": "Medya",
-  "account.mention": "@{name} kişisinden bahset",
+  "account.mention": "@{name}'i an",
   "account.moved_to": "{name} şuraya taşındı:",
-  "account.mute": "@{name} adlı kişiyi sessize al",
-  "account.mute_notifications": "@{name} adlı kişinin bildirimlerini kapat",
+  "account.mute": "@{name}'i susstur",
+  "account.mute_notifications": "@{name}'in bildirimlerini sustur",
   "account.muted": "Susturuldu",
   "account.posts": "Gönderiler",
   "account.posts_with_replies": "Gönderiler ve yanıtlar",
-  "account.report": "@{name} adlı kişiyi bildir",
+  "account.report": "@{name}'i şikayet et",
   "account.requested": "Onay bekleniyor. Takip isteğini iptal etmek için tıklayın",
-  "account.share": "@{name} adlı kişinin profilini paylaş",
+  "account.share": "@{name}'in profilini paylaş",
   "account.show_reblogs": "@{name} kişisinin boostlarını göster",
   "account.statuses_counter": "{count, plural, one {{counter} Gönderi} other {{counter} Gönderi}}",
   "account.unblock": "@{name} adlı kişinin engelini kaldır",
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Hay aksi!",
   "announcement.announcement": "Duyuru",
   "attachments_list.unprocessed": "(işlenmemiş)",
+  "audio.hide": "Sesi gizle",
   "autosuggest_hashtag.per_week": "Haftada {count}",
   "boost_modal.combo": "Bir daha ki sefere {combo} tuşuna basabilirsin",
   "bundle_column_error.body": "Bu bileşen yüklenirken bir şeyler ters gitti.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Haberler",
   "explore.trending_statuses": "Gönderiler",
   "explore.trending_tags": "Etiketler",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Tamam",
   "follow_recommendations.heading": "Gönderilerini görmek isteyeceğiniz kişileri takip edin! Burada bazı öneriler bulabilirsiniz.",
   "follow_recommendations.lead": "Takip ettiğiniz kişilerin gönderileri anasayfa akışınızda kronolojik sırada görünmeye devam edecek. Hata yapmaktan çekinmeyin, kişileri istediğiniz anda kolayca takipten çıkabilirsiniz!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Herhangi biri",
   "hashtag.column_settings.tag_mode.none": "Bunların hiçbiri",
   "hashtag.column_settings.tag_toggle": "Bu sütundaki ek etiketleri içer",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Etiketi takip et",
   "hashtag.total_volume": "Son {days, plural, one {gündeki} other {{days} gündeki}} toplam hacim",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Etiketi takibi bırak",
   "home.column_settings.basic": "Temel",
   "home.column_settings.show_reblogs": "Boostları göster",
   "home.column_settings.show_replies": "Yanıtları göster",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "{count, plural, one {{count} kez} other {{count} kez}} düzenlendi",
   "status.embed": "Gömülü",
   "status.favourite": "Favorilerine ekle",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtrelenmiş",
   "status.hide": "Gönderiyi sakla",
   "status.history.created": "{name} oluşturdu {date}",
diff --git a/app/javascript/mastodon/locales/tt.json b/app/javascript/mastodon/locales/tt.json
index c9a48d37c..c2739e181 100644
--- a/app/javascript/mastodon/locales/tt.json
+++ b/app/javascript/mastodon/locales/tt.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ой!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/ug.json b/app/javascript/mastodon/locales/ug.json
index 99fdcfd45..c77444bff 100644
--- a/app/javascript/mastodon/locales/ug.json
+++ b/app/javascript/mastodon/locales/ug.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "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.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 727b0b994..e1b10445d 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ой!",
   "announcement.announcement": "Оголошення",
   "attachments_list.unprocessed": "(не оброблено)",
+  "audio.hide": "Сховати аудіо",
   "autosuggest_hashtag.per_week": "{count} в тиждень",
   "boost_modal.combo": "Ви можете натиснути {combo}, щоб пропустити це наступного разу",
   "bundle_column_error.body": "Щось пішло не так під час завантаження цього компоненту.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Новини",
   "explore.trending_statuses": "Дописи",
   "explore.trending_tags": "Хештеґи",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Готово",
   "follow_recommendations.heading": "Підпишіться на людей, чиї дописи ви хочете бачити! Ось деякі пропозиції.",
   "follow_recommendations.lead": "Дописи від людей, за якими ви стежите, з'являться в хронологічному порядку у вашій домашній стрічці. Не бійся помилятися, ви можете відписатися від людей так само легко в будь-який час!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Який-небудь зі списку",
   "hashtag.column_settings.tag_mode.none": "Жоден зі списку",
   "hashtag.column_settings.tag_toggle": "Додати додаткові теґи до цього стовпчика",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Стежити за хештегом",
   "hashtag.total_volume": "Загальний обсяг за останні(й) {days, plural, one {день} few {{days} дні} other {{days} днів}}",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Не стежити за хештегом",
   "home.column_settings.basic": "Основні",
   "home.column_settings.show_reblogs": "Показувати поширення",
   "home.column_settings.show_replies": "Показувати відповіді",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Відредаговано {count, plural, one {{count} раз} few {{count} рази} many {{counter} разів} other {{counter} разів}}",
   "status.embed": "Вбудувати",
   "status.favourite": "Подобається",
+  "status.filter": "Filter this post",
   "status.filtered": "Відфільтровано",
   "status.hide": "Сховати дмух",
   "status.history.created": "{name} створює {date}",
diff --git a/app/javascript/mastodon/locales/ur.json b/app/javascript/mastodon/locales/ur.json
index b3e3fd771..19cee9c2a 100644
--- a/app/javascript/mastodon/locales/ur.json
+++ b/app/javascript/mastodon/locales/ur.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "ا رے!",
   "announcement.announcement": "اعلان",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} فی ہفتہ",
   "boost_modal.combo": "آئیندہ یہ نہ دیکھنے کیلئے آپ {combo} دبا سکتے ہیں",
   "bundle_column_error.body": "اس عنصر کو برآمد کرتے وقت کچھ خرابی پیش آئی ہے.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json
index 4cdb1e53d..3dc6db112 100644
--- a/app/javascript/mastodon/locales/vi.json
+++ b/app/javascript/mastodon/locales/vi.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Ốiii!",
   "announcement.announcement": "Có gì mới?",
   "attachments_list.unprocessed": "(chưa xử lí)",
+  "audio.hide": "Ẩn âm thanh",
   "autosuggest_hashtag.per_week": "{count} mỗi tuần",
   "boost_modal.combo": "Nhấn {combo} để bỏ qua bước này",
   "bundle_column_error.body": "Đã có lỗi xảy ra trong khi tải nội dung này.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "Tin tức",
   "explore.trending_statuses": "Tút",
   "explore.trending_tags": "Hashtag",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Xong",
   "follow_recommendations.heading": "Theo dõi những người bạn muốn đọc tút của họ! Dưới đây là vài gợi ý.",
   "follow_recommendations.lead": "Tút từ những người bạn theo dõi sẽ hiện theo thứ tự thời gian trên bảng tin. Đừng ngại, bạn có thể dễ dàng ngưng theo dõi họ bất cứ lúc nào!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "Một phần",
   "hashtag.column_settings.tag_mode.none": "Không chọn",
   "hashtag.column_settings.tag_toggle": "Bao gồm thêm hashtag cho cột này",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "Theo dõi hashtag",
   "hashtag.total_volume": "Tổng số lần sử dụng {days, plural, other {{days} ngày}} qua",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "Ngưng theo dõi hashtag",
   "home.column_settings.basic": "Tùy chỉnh",
   "home.column_settings.show_reblogs": "Hiện những lượt đăng lại",
   "home.column_settings.show_replies": "Hiện những tút dạng trả lời",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Đã sửa {count, plural, other {{count} lần}}",
   "status.embed": "Nhúng",
   "status.favourite": "Thích",
+  "status.filter": "Filter this post",
   "status.filtered": "Bộ lọc",
   "status.hide": "Ẩn tút",
   "status.history.created": "{name} tạo lúc {date}",
diff --git a/app/javascript/mastodon/locales/zgh.json b/app/javascript/mastodon/locales/zgh.json
index 898cc22a9..92201375d 100644
--- a/app/javascript/mastodon/locales/zgh.json
+++ b/app/javascript/mastodon/locales/zgh.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "Oops!",
   "announcement.announcement": "Announcement",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} ⵙ ⵉⵎⴰⵍⴰⵙⵙ",
   "boost_modal.combo": "You can press {combo} to skip this next time",
   "bundle_column_error.body": "Something went wrong while loading this component.",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "Done",
   "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
   "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
+  "status.filter": "Filter this post",
   "status.filtered": "Filtered",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 334b93034..9241eeec8 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "哎呀!",
   "announcement.announcement": "公告",
   "attachments_list.unprocessed": "(未处理)",
+  "audio.hide": "隐藏音频",
   "autosuggest_hashtag.per_week": "每星期 {count} 条",
   "boost_modal.combo": "下次按住 {combo} 即可跳过此提示",
   "bundle_column_error.body": "载入这个组件时发生了错误。",
@@ -109,8 +110,8 @@
   "compose_form.publish": "发布",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.save_changes": "保存更改",
-  "compose_form.sensitive.hide": "{count, plural, one {将媒体标记为敏感内容} other {将媒体标记为敏感内容}}",
-  "compose_form.sensitive.marked": "{count, plural, one {媒体已被标记为敏感内容} other {媒体已被标记为敏感内容}}",
+  "compose_form.sensitive.hide": "标记媒体为敏感内容",
+  "compose_form.sensitive.marked": "媒体已被标记为敏感内容",
   "compose_form.sensitive.unmarked": "媒体未被标记为敏感内容",
   "compose_form.spoiler.marked": "移除内容警告",
   "compose_form.spoiler.unmarked": "添加内容警告",
@@ -196,6 +197,22 @@
   "explore.trending_links": "最新消息",
   "explore.trending_statuses": "嘟文",
   "explore.trending_tags": "话题标签",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "完成",
   "follow_recommendations.heading": "关注你感兴趣的用户!这里有一些推荐。",
   "follow_recommendations.lead": "你关注的人的嘟文将按时间顺序在你的主页上显示。 别担心,你可以随时取消关注!",
@@ -203,8 +220,8 @@
   "follow_request.reject": "拒绝",
   "follow_requests.unlocked_explanation": "尽管你没有锁嘟,但是 {domain} 的工作人员认为你也许会想手动审核审核这些账号的关注请求。",
   "generic.saved": "已保存",
-  "getting_started.developers": "开发",
-  "getting_started.directory": "用户目录",
+  "getting_started.developers": "开发者",
+  "getting_started.directory": "个人资料目录",
   "getting_started.documentation": "文档",
   "getting_started.heading": "开始使用",
   "getting_started.invite": "邀请用户",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "任一",
   "hashtag.column_settings.tag_mode.none": "无一",
   "hashtag.column_settings.tag_toggle": "在此栏加入额外的标签",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "关注哈希标签",
   "hashtag.total_volume": "在过去的{days, plural,one {day}other {{days}days}}的总数量",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "取消关注哈希标签",
   "home.column_settings.basic": "基本设置",
   "home.column_settings.show_reblogs": "显示转嘟",
   "home.column_settings.show_replies": "显示回复",
@@ -436,7 +453,7 @@
   "report.thanks.title_actionable": "感谢提交举报,我们将会进行处理。",
   "report.unfollow": "取消关注 @{name}",
   "report.unfollow_explanation": "你正在关注此账户。如果要想在你的主页上不再看到他们的帖子,取消对他们的关注即可。",
-  "report_notification.attached_statuses": "{count, plural, one {{count} 嘟文} other {{count} 嘟文}} 附件",
+  "report_notification.attached_statuses": "附上 {count} 条嘟文",
   "report_notification.categories.other": "其他",
   "report_notification.categories.spam": "骚扰",
   "report_notification.categories.violation": "违反规则",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "共编辑 {count, plural, one {{count} 次} other {{count} 次}}",
   "status.embed": "嵌入",
   "status.favourite": "喜欢",
+  "status.filter": "Filter this post",
   "status.filtered": "已过滤",
   "status.hide": "屏蔽嘟文",
   "status.history.created": "{name} 创建于 {date}",
@@ -520,7 +538,7 @@
   "timeline_hint.resources.followers": "关注者",
   "timeline_hint.resources.follows": "关注",
   "timeline_hint.resources.statuses": "更早的嘟文",
-  "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {{days} days}}",
+  "trends.counter_by_accounts": "过去 {day} 天有 {counter} 人讨论",
   "trends.trending_now": "现在流行",
   "ui.beforeunload": "如果你现在离开 Mastodon,你的草稿内容将会丢失。",
   "units.short.billion": "{count} B",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index e3c65cdab..fdc206800 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "噢!",
   "announcement.announcement": "公告",
   "attachments_list.unprocessed": "(unprocessed)",
+  "audio.hide": "Hide audio",
   "autosuggest_hashtag.per_week": "{count} / 週",
   "boost_modal.combo": "如你想在下次路過這顯示,請按{combo},",
   "bundle_column_error.body": "加載本組件出錯。",
@@ -196,6 +197,22 @@
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "完成",
   "follow_recommendations.heading": "跟隨人們以看到來自他們的嘟文!這裡有些建議。",
   "follow_recommendations.lead": "您跟隨對象知嘟文將會以時間順序顯示於您的 home feed 上。別擔心犯下錯誤,您隨時可以取消跟隨人們!",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "嵌入",
   "status.favourite": "最愛",
+  "status.filter": "Filter this post",
   "status.filtered": "已過濾",
   "status.hide": "Hide toot",
   "status.history.created": "{name} created {date}",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index 99814b30d..13eee62de 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -59,6 +59,7 @@
   "alert.unexpected.title": "哎呀!",
   "announcement.announcement": "公告",
   "attachments_list.unprocessed": "(未經處理)",
+  "audio.hide": "隱藏音訊",
   "autosuggest_hashtag.per_week": "{count} / 週",
   "boost_modal.combo": "下次您可以按 {combo} 跳過",
   "bundle_column_error.body": "載入此元件時發生錯誤。",
@@ -196,6 +197,22 @@
   "explore.trending_links": "最新消息",
   "explore.trending_statuses": "嘟文",
   "explore.trending_tags": "主題標籤",
+  "filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
+  "filter_modal.added.context_mismatch_title": "Context mismatch!",
+  "filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
+  "filter_modal.added.expired_title": "Expired filter!",
+  "filter_modal.added.review_and_configure": "To review and further configure this filter category, go to the {settings_link}.",
+  "filter_modal.added.review_and_configure_title": "Filter settings",
+  "filter_modal.added.settings_link": "settings page",
+  "filter_modal.added.short_explanation": "This post has been added to the following filter category: {title}.",
+  "filter_modal.added.title": "Filter added!",
+  "filter_modal.select_filter.context_mismatch": "does not apply to this context",
+  "filter_modal.select_filter.expired": "expired",
+  "filter_modal.select_filter.prompt_new": "New category: {name}",
+  "filter_modal.select_filter.search": "Search or create",
+  "filter_modal.select_filter.subtitle": "Use an existing category or create a new one",
+  "filter_modal.select_filter.title": "Filter this post",
+  "filter_modal.title.status": "Filter a post",
   "follow_recommendations.done": "完成",
   "follow_recommendations.heading": "跟隨您想檢視其嘟文的人!這裡有一些建議。",
   "follow_recommendations.lead": "來自您跟隨的人之嘟文將會按時間順序顯示在您的首頁時間軸上。不要害怕犯錯,您隨時都可以取消跟隨其他人!",
@@ -220,9 +237,9 @@
   "hashtag.column_settings.tag_mode.any": "任一",
   "hashtag.column_settings.tag_mode.none": "全不",
   "hashtag.column_settings.tag_toggle": "將額外標籤加入到這個欄位",
-  "hashtag.follow": "Follow hashtag",
+  "hashtag.follow": "追蹤主題標籤",
   "hashtag.total_volume": "過去 {days, plural, one {日} other {{days} 日}} 之總量",
-  "hashtag.unfollow": "Unfollow hashtag",
+  "hashtag.unfollow": "取消追蹤主題標籤",
   "home.column_settings.basic": "基本",
   "home.column_settings.show_reblogs": "顯示轉嘟",
   "home.column_settings.show_replies": "顯示回覆",
@@ -470,6 +487,7 @@
   "status.edited_x_times": "已編輯 {count, plural, one {{count} 次} other {{count} 次}}",
   "status.embed": "內嵌",
   "status.favourite": "最愛",
+  "status.filter": "Filter this post",
   "status.filtered": "已過濾",
   "status.hide": "隱藏嘟文",
   "status.history.created": "{name} 於 {date} 建立",
diff --git a/app/javascript/mastodon/reducers/filters.js b/app/javascript/mastodon/reducers/filters.js
index 14b704027..f4f97cd3a 100644
--- a/app/javascript/mastodon/reducers/filters.js
+++ b/app/javascript/mastodon/reducers/filters.js
@@ -1,4 +1,5 @@
 import { FILTERS_IMPORT } from '../actions/importer';
+import { FILTERS_FETCH_SUCCESS, FILTERS_CREATE_SUCCESS } from '../actions/filters';
 import { Map as ImmutableMap, is, fromJS } from 'immutable';
 
 const normalizeFilter = (state, filter) => {
@@ -7,13 +8,17 @@ const normalizeFilter = (state, filter) => {
     title: filter.title,
     context: filter.context,
     filter_action: filter.filter_action,
+    keywords: filter.keywords,
     expires_at: filter.expires_at ? Date.parse(filter.expires_at) : null,
   });
 
   if (is(state.get(filter.id), normalizedFilter)) {
     return state;
   } else {
-    return state.set(filter.id, normalizedFilter);
+    // Do not overwrite keywords when receiving a partial filter
+    return state.update(filter.id, ImmutableMap(), (old) => (
+      old.mergeWith(((old_value, new_value) => (new_value === undefined ? old_value : new_value)), normalizedFilter)
+    ));
   }
 };
 
@@ -27,6 +32,10 @@ const normalizeFilters = (state, filters) => {
 
 export default function filters(state = ImmutableMap(), action) {
   switch(action.type) {
+  case FILTERS_CREATE_SUCCESS:
+    return normalizeFilter(state, action.filter);
+  case FILTERS_FETCH_SUCCESS:
+    return normalizeFilters(ImmutableMap(), action.filters);
   case FILTERS_IMPORT:
     return normalizeFilters(state, action.filters);
   default:
diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js
index 4b460bc10..eb34edb63 100644
--- a/app/javascript/mastodon/reducers/notifications.js
+++ b/app/javascript/mastodon/reducers/notifications.js
@@ -41,7 +41,7 @@ const initialState = ImmutableMap({
   lastReadId: '0',
   readMarkerId: '0',
   isTabVisible: true,
-  isLoading: false,
+  isLoading: 0,
   browserSupport: false,
   browserPermission: 'default',
 });
@@ -115,7 +115,7 @@ const expandNormalizedNotifications = (state, notifications, next, isLoadingRece
       }
     }
 
-    mutable.set('isLoading', false);
+    mutable.update('isLoading', (nbLoading) => nbLoading - 1);
   });
 };
 
@@ -214,9 +214,9 @@ export default function notifications(state = initialState, action) {
   case NOTIFICATIONS_LOAD_PENDING:
     return state.update('items', list => state.get('pendingItems').concat(list.take(40))).set('pendingItems', ImmutableList()).set('unread', 0);
   case NOTIFICATIONS_EXPAND_REQUEST:
-    return state.set('isLoading', true);
+    return state.update('isLoading', (nbLoading) => nbLoading + 1);
   case NOTIFICATIONS_EXPAND_FAIL:
-    return state.set('isLoading', false);
+    return state.update('isLoading', (nbLoading) => nbLoading - 1);
   case NOTIFICATIONS_FILTER_SET:
     return state.set('items', ImmutableList()).set('pendingItems', ImmutableList()).set('hasMore', true);
   case NOTIFICATIONS_SCROLL_TOP:
@@ -234,8 +234,6 @@ export default function notifications(state = initialState, action) {
   case FOLLOW_REQUEST_AUTHORIZE_SUCCESS:
   case FOLLOW_REQUEST_REJECT_SUCCESS:
     return filterNotifications(state, [action.id], 'follow_request');
-  case ACCOUNT_MUTE_SUCCESS:
-    return action.relationship.muting_notifications ? filterNotifications(state, [action.relationship.id]) : state;
   case NOTIFICATIONS_CLEAR:
     return state.set('items', ImmutableList()).set('pendingItems', ImmutableList()).set('hasMore', false);
   case TIMELINE_DELETE:
diff --git a/app/javascript/mastodon/selectors/index.js b/app/javascript/mastodon/selectors/index.js
index 187e3306d..3dd7f4897 100644
--- a/app/javascript/mastodon/selectors/index.js
+++ b/app/javascript/mastodon/selectors/index.js
@@ -1,5 +1,6 @@
 import { createSelector } from 'reselect';
 import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
+import { toServerSideType } from 'mastodon/utils/filters';
 import { me } from '../initial_state';
 
 const getAccountBase         = (state, id) => state.getIn(['accounts', id], null);
@@ -20,23 +21,6 @@ export const makeGetAccount = () => {
   });
 };
 
-const toServerSideType = columnType => {
-  switch (columnType) {
-  case 'home':
-  case 'notifications':
-  case 'public':
-  case 'thread':
-  case 'account':
-    return columnType;
-  default:
-    if (columnType.indexOf('list:') > -1) {
-      return 'home';
-    } else {
-      return 'public'; // community, account, hashtag
-    }
-  }
-};
-
 const getFilters = (state, { contextType }) => {
   if (!contextType) return null;
 
@@ -73,6 +57,7 @@ export const makeGetStatus = () => {
         if (filterResults.some((result) => filters.getIn([result.get('filter'), 'filter_action']) === 'hide')) {
           return null;
         }
+        filterResults = filterResults.filter(result => filters.has(result.get('filter')));
         if (!filterResults.isEmpty()) {
           filtered = filterResults.map(result => filters.getIn([result.get('filter'), 'title']));
         }
diff --git a/app/javascript/mastodon/utils/filters.js b/app/javascript/mastodon/utils/filters.js
new file mode 100644
index 000000000..97b433a99
--- /dev/null
+++ b/app/javascript/mastodon/utils/filters.js
@@ -0,0 +1,16 @@
+export const toServerSideType = columnType => {
+  switch (columnType) {
+  case 'home':
+  case 'notifications':
+  case 'public':
+  case 'thread':
+  case 'account':
+    return columnType;
+  default:
+    if (columnType.indexOf('list:') > -1) {
+      return 'home';
+    } else {
+      return 'public'; // community, account, hashtag
+    }
+  }
+};
diff --git a/app/javascript/mastodon/utils/icons.js b/app/javascript/mastodon/utils/icons.js
new file mode 100644
index 000000000..be566032e
--- /dev/null
+++ b/app/javascript/mastodon/utils/icons.js
@@ -0,0 +1,13 @@
+// Copied from emoji-mart for consistency with emoji picker and since
+// they don't export the icons in the package
+export const loupeIcon = (
+  <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'>
+    <path d='M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z' />
+  </svg>
+);
+
+export const deleteIcon = (
+  <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'>
+    <path d='M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z' />
+  </svg>
+);
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index e9e9a2faa..00f654082 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -5233,6 +5233,16 @@ a.status-card.compact:hover {
     line-height: 22px;
     color: lighten($inverted-text-color, 16%);
     margin-bottom: 30px;
+
+    a {
+      text-decoration: none;
+      color: $inverted-text-color;
+      font-weight: 500;
+
+      &:hover {
+        text-decoration: underline;
+      }
+    }
   }
 
   &__actions {
@@ -5379,6 +5389,14 @@ a.status-card.compact:hover {
     background: transparent;
     margin: 15px 0;
   }
+
+  .emoji-mart-search {
+    padding-right: 10px;
+  }
+
+  .emoji-mart-search-icon {
+    right: 10px + 5px;
+  }
 }
 
 .report-modal__container {
@@ -5939,6 +5957,13 @@ a.status-card.compact:hover {
     height: 100%;
   }
 
+  &.inactive {
+    audio,
+    .video-player__controls {
+      visibility: hidden;
+    }
+  }
+
   .video-player__volume::before,
   .video-player__seek::before {
     background: currentColor;
diff --git a/app/lib/importer/statuses_index_importer.rb b/app/lib/importer/statuses_index_importer.rb
index 7c6532560..5b5153d5c 100644
--- a/app/lib/importer/statuses_index_importer.rb
+++ b/app/lib/importer/statuses_index_importer.rb
@@ -84,6 +84,6 @@ class Importer::StatusesIndexImporter < Importer::BaseImporter
   end
 
   def local_statuses_scope
-    Status.local.select('id, coalesce(reblog_of_id, id) as status_id')
+    Status.local.select('"statuses"."id", COALESCE("statuses"."reblog_of_id", "statuses"."id") AS status_id')
   end
 end
diff --git a/app/lib/request.rb b/app/lib/request.rb
index 4289da933..f5123d776 100644
--- a/app/lib/request.rb
+++ b/app/lib/request.rb
@@ -31,7 +31,7 @@ class Request
     @url         = Addressable::URI.parse(url).normalize
     @http_client = options.delete(:http_client)
     @options     = options.merge(socket_class: use_proxy? ? ProxySocket : Socket)
-    @options     = @options.merge(Rails.configuration.x.http_client_proxy) if use_proxy?
+    @options     = @options.merge(proxy_url) if use_proxy?
     @headers     = {}
 
     raise Mastodon::HostValidationError, 'Instance does not support hidden service connections' if block_hidden_service?
@@ -141,11 +141,23 @@ class Request
   end
 
   def use_proxy?
-    Rails.configuration.x.http_client_proxy.present?
+    proxy_url.present?
+  end
+
+  def proxy_url
+    if hidden_service? && Rails.configuration.x.http_client_hidden_proxy.present?
+      Rails.configuration.x.http_client_hidden_proxy
+    else
+      Rails.configuration.x.http_client_proxy
+    end
   end
 
   def block_hidden_service?
-    !Rails.configuration.x.access_to_hidden_service && /\.(onion|i2p)$/.match?(@url.host)
+    !Rails.configuration.x.access_to_hidden_service && hidden_service?
+  end
+
+  def hidden_service?
+    /\.(onion|i2p)$/.match?(@url.host)
   end
 
   module ClientLimit
diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb
index a7401362f..9b358d338 100644
--- a/app/models/concerns/account_interactions.rb
+++ b/app/models/concerns/account_interactions.rb
@@ -249,15 +249,7 @@ module AccountInteractions
 
   def status_matches_filters(status)
     active_filters = CustomFilter.cached_filters_for(id)
-
-    filter_matches = active_filters.filter_map do |filter, rules|
-      next if rules[:keywords].blank?
-
-      match = rules[:keywords].match(status.proper.searchable_text)
-      FilterResultPresenter.new(filter: filter, keyword_matches: [match.to_s]) unless match.nil?
-    end
-
-    filter_matches
+    CustomFilter.apply_cached_filters(active_filters, status)
   end
 
   def followers_for_local_distribution
diff --git a/app/models/custom_filter.rb b/app/models/custom_filter.rb
index 985eab125..da2a91493 100644
--- a/app/models/custom_filter.rb
+++ b/app/models/custom_filter.rb
@@ -34,6 +34,7 @@ class CustomFilter < ApplicationRecord
 
   belongs_to :account
   has_many :keywords, class_name: 'CustomFilterKeyword', foreign_key: :custom_filter_id, inverse_of: :custom_filter, dependent: :destroy
+  has_many :statuses, class_name: 'CustomFilterStatus', foreign_key: :custom_filter_id, inverse_of: :custom_filter, dependent: :destroy
   accepts_nested_attributes_for :keywords, reject_if: :all_blank, allow_destroy: true
 
   validates :title, :context, presence: true
@@ -62,8 +63,10 @@ class CustomFilter < ApplicationRecord
 
   def self.cached_filters_for(account_id)
     active_filters = Rails.cache.fetch("filters:v3:#{account_id}") do
+      filters_hash = {}
+
       scope = CustomFilterKeyword.includes(:custom_filter).where(custom_filter: { account_id: account_id }).where(Arel.sql('expires_at IS NULL OR expires_at > NOW()'))
-      scope.to_a.group_by(&:custom_filter).map do |filter, keywords|
+      scope.to_a.group_by(&:custom_filter).each do |filter, keywords|
         keywords.map! do |keyword|
           if keyword.whole_word
             sb = /\A[[:word:]]/.match?(keyword.keyword) ? '\b' : ''
@@ -74,13 +77,34 @@ class CustomFilter < ApplicationRecord
             /#{Regexp.escape(keyword.keyword)}/i
           end
         end
-        [filter, { keywords: Regexp.union(keywords) }]
+
+        filters_hash[filter.id] = { keywords: Regexp.union(keywords), filter: filter }
+      end.to_h
+
+      scope = CustomFilterStatus.includes(:custom_filter).where(custom_filter: { account_id: account_id }).where(Arel.sql('expires_at IS NULL OR expires_at > NOW()'))
+      scope.to_a.group_by(&:custom_filter).each do |filter, statuses|
+        filters_hash[filter.id] ||= { filter: filter }
+        filters_hash[filter.id].merge!(status_ids: statuses.map(&:status_id))
       end
+
+      filters_hash.values.map { |cache| [cache.delete(:filter), cache] }
     end.to_a
 
     active_filters.select { |custom_filter, _| !custom_filter.expired? }
   end
 
+  def self.apply_cached_filters(cached_filters, status)
+    cached_filters.filter_map do |filter, rules|
+      match = rules[:keywords].match(status.proper.searchable_text) if rules[:keywords].present?
+      keyword_matches = [match.to_s] unless match.nil?
+
+      status_matches = [status.id, status.reblog_of_id].compact & rules[:status_ids] if rules[:status_ids].present?
+
+      next if keyword_matches.blank? && status_matches.blank?
+      FilterResultPresenter.new(filter: filter, keyword_matches: keyword_matches, status_matches: status_matches)
+    end
+  end
+
   def prepare_cache_invalidation!
     @should_invalidate_cache = true
   end
diff --git a/app/models/custom_filter_status.rb b/app/models/custom_filter_status.rb
new file mode 100644
index 000000000..b6bea1394
--- /dev/null
+++ b/app/models/custom_filter_status.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+# == Schema Information
+#
+# Table name: custom_filter_statuses
+#
+#  id               :bigint(8)        not null, primary key
+#  custom_filter_id :bigint(8)        not null
+#  status_id        :bigint(8)        default(""), not null
+#  created_at       :datetime         not null
+#  updated_at       :datetime         not null
+#
+
+class CustomFilterStatus < ApplicationRecord
+  belongs_to :custom_filter
+  belongs_to :status
+
+  validates :status, uniqueness: { scope: :custom_filter }
+  validate :validate_status_access
+
+  before_save :prepare_cache_invalidation!
+  before_destroy :prepare_cache_invalidation!
+  after_commit :invalidate_cache!
+
+  private
+
+  def validate_status_access
+    errors.add(:status_id, :invalid) unless StatusPolicy.new(custom_filter.account, status).show?
+  end
+
+  def prepare_cache_invalidation!
+    custom_filter.prepare_cache_invalidation!
+  end
+
+  def invalidate_cache!
+    custom_filter.invalidate_cache!
+  end
+end
diff --git a/app/models/email_domain_block.rb b/app/models/email_domain_block.rb
index 0e1e663c1..f9d74332b 100644
--- a/app/models/email_domain_block.rb
+++ b/app/models/email_domain_block.rb
@@ -30,32 +30,56 @@ class EmailDomainBlock < ApplicationRecord
     @history ||= Trends::History.new('email_domain_blocks', id)
   end
 
-  def self.block?(domain_or_domains, attempt_ip: nil)
-    domains = Array(domain_or_domains).map do |str|
-      domain = begin
-        if str.include?('@')
-          str.split('@', 2).last
-        else
-          str
-        end
-      end
+  class Matcher
+    def initialize(domain_or_domains, attempt_ip: nil)
+      @uris       = extract_uris(domain_or_domains)
+      @attempt_ip = attempt_ip
+    end
 
-      TagManager.instance.normalize_domain(domain) if domain.present?
-    rescue Addressable::URI::InvalidURIError
-      nil
+    def match?
+      blocking? || invalid_uri?
     end
 
-    # If some of the inputs passed in are invalid, we definitely want to
-    # block the attempt, but we also want to register hits against any
-    # other valid matches
+    private
 
-    blocked = domains.any?(&:nil?)
+    def invalid_uri?
+      @uris.any?(&:nil?)
+    end
 
-    where(domain: domains).find_each do |block|
-      blocked = true
-      block.history.add(attempt_ip) if attempt_ip.present?
+    def blocking?
+      blocks = EmailDomainBlock.where(domain: domains_with_variants).order(Arel.sql('char_length(domain) desc'))
+      blocks.each { |block| block.history.add(@attempt_ip) } if @attempt_ip.present?
+      blocks.any?
     end
 
-    blocked
+    def domains_with_variants
+      @uris.flat_map do |uri|
+        next if uri.nil?
+
+        segments = uri.normalized_host.split('.')
+
+        segments.map.with_index { |_, i| segments[i..-1].join('.') }
+      end
+    end
+
+    def extract_uris(domain_or_domains)
+      Array(domain_or_domains).map do |str|
+        domain = begin
+          if str.include?('@')
+            str.split('@', 2).last
+          else
+            str
+          end
+        end
+
+        Addressable::URI.new.tap { |u| u.host = domain.strip } if domain.present?
+      rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError
+        nil
+      end
+    end
+  end
+
+  def self.block?(domain_or_domains, attempt_ip: nil)
+    Matcher.new(domain_or_domains, attempt_ip: attempt_ip).match?
   end
 end
diff --git a/app/models/form/status_filter_batch_action.rb b/app/models/form/status_filter_batch_action.rb
new file mode 100644
index 000000000..d87bd5cc4
--- /dev/null
+++ b/app/models/form/status_filter_batch_action.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+class Form::StatusFilterBatchAction
+  include ActiveModel::Model
+  include AccountableConcern
+  include Authorization
+
+  attr_accessor :current_account, :type,
+                :status_filter_ids, :filter_id
+
+  def save!
+    process_action!
+  end
+
+  private
+
+  def status_filters
+    filter = current_account.custom_filters.find(filter_id)
+    filter.statuses.where(id: status_filter_ids)
+  end
+
+  def process_action!
+    return if status_filter_ids.empty?
+
+    case type
+    when 'remove'
+      handle_remove!
+    end
+  end
+
+  def handle_remove!
+    status_filters.destroy_all
+  end
+end
diff --git a/app/models/ip_block.rb b/app/models/ip_block.rb
index aedd3ca0d..e1ab59806 100644
--- a/app/models/ip_block.rb
+++ b/app/models/ip_block.rb
@@ -19,6 +19,7 @@ class IpBlock < ApplicationRecord
 
   enum severity: {
     sign_up_requires_approval: 5000,
+    sign_up_block: 5500,
     no_access: 9999,
   }
 
diff --git a/app/models/user.rb b/app/models/user.rb
index ffad4ae5a..46f66526e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -94,7 +94,7 @@ class User < ApplicationRecord
   validates :invite_request, presence: true, on: :create, if: :invite_text_required?
 
   validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale?
-  validates_with BlacklistedEmailValidator, if: -> { !confirmed? }
+  validates_with BlacklistedEmailValidator, if: -> { ENV['EMAIL_DOMAIN_LISTS_APPLY_AFTER_CONFIRMATION'] == 'true' || !confirmed? }
   validates_with EmailMxValidator, if: :validate_email_dns?
   validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
 
diff --git a/app/presenters/filter_result_presenter.rb b/app/presenters/filter_result_presenter.rb
index 677225f5e..1e9e8f3c1 100644
--- a/app/presenters/filter_result_presenter.rb
+++ b/app/presenters/filter_result_presenter.rb
@@ -1,5 +1,5 @@
 # frozen_string_literal: true
 
 class FilterResultPresenter < ActiveModelSerializers::Model
-  attributes :filter, :keyword_matches
+  attributes :filter, :keyword_matches, :status_matches
 end
diff --git a/app/presenters/status_relationships_presenter.rb b/app/presenters/status_relationships_presenter.rb
index d7ffb1954..be818a2de 100644
--- a/app/presenters/status_relationships_presenter.rb
+++ b/app/presenters/status_relationships_presenter.rb
@@ -33,12 +33,7 @@ class StatusRelationshipsPresenter
     active_filters = CustomFilter.cached_filters_for(current_account_id)
 
     @filters_map = statuses.each_with_object({}) do |status, h|
-      filter_matches = active_filters.filter_map do |filter, rules|
-        next if rules[:keywords].blank?
-
-        match = rules[:keywords].match(status.proper.searchable_text)
-        FilterResultPresenter.new(filter: filter, keyword_matches: [match.to_s]) unless match.nil?
-      end
+      filter_matches = CustomFilter.apply_cached_filters(active_filters, status)
 
       unless filter_matches.empty?
         h[status.id] = filter_matches
diff --git a/app/serializers/rest/filter_result_serializer.rb b/app/serializers/rest/filter_result_serializer.rb
index 0ef4db79a..54ead2f1f 100644
--- a/app/serializers/rest/filter_result_serializer.rb
+++ b/app/serializers/rest/filter_result_serializer.rb
@@ -3,4 +3,9 @@
 class REST::FilterResultSerializer < ActiveModel::Serializer
   belongs_to :filter, serializer: REST::FilterSerializer
   has_many :keyword_matches
+  has_many :status_matches
+
+  def status_matches
+    object.status_matches&.map(&:to_s)
+  end
 end
diff --git a/app/serializers/rest/filter_serializer.rb b/app/serializers/rest/filter_serializer.rb
index 98d7edb17..8816dd807 100644
--- a/app/serializers/rest/filter_serializer.rb
+++ b/app/serializers/rest/filter_serializer.rb
@@ -3,6 +3,7 @@
 class REST::FilterSerializer < ActiveModel::Serializer
   attributes :id, :title, :context, :expires_at, :filter_action
   has_many :keywords, serializer: REST::FilterKeywordSerializer, if: :rules_requested?
+  has_many :statuses, serializer: REST::FilterStatusSerializer, if: :rules_requested?
 
   def id
     object.id.to_s
diff --git a/app/serializers/rest/filter_status_serializer.rb b/app/serializers/rest/filter_status_serializer.rb
new file mode 100644
index 000000000..6bcbaa249
--- /dev/null
+++ b/app/serializers/rest/filter_status_serializer.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class REST::FilterStatusSerializer < ActiveModel::Serializer
+  attributes :id, :status_id
+
+  def id
+    object.id.to_s
+  end
+
+  def status_id
+    object.status_id.to_s
+  end
+end
diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb
index 4449a5427..34750dba6 100644
--- a/app/services/activitypub/process_account_service.rb
+++ b/app/services/activitypub/process_account_service.rb
@@ -105,11 +105,13 @@ class ActivityPub::ProcessAccountService < BaseService
   def set_fetchable_attributes!
     begin
       @account.avatar_remote_url = image_url('icon') || '' unless skip_download?
+      @account.avatar = nil if @account.avatar_remote_url.blank?
     rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError
       RedownloadAvatarWorker.perform_in(rand(30..600).seconds, @account.id)
     end
     begin
       @account.header_remote_url = image_url('image') || '' unless skip_download?
+      @account.header = nil if @account.header_remote_url.blank?
     rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError
       RedownloadHeaderWorker.perform_in(rand(30..600).seconds, @account.id)
     end
diff --git a/app/services/app_sign_up_service.rb b/app/services/app_sign_up_service.rb
index e00694157..3833327bb 100644
--- a/app/services/app_sign_up_service.rb
+++ b/app/services/app_sign_up_service.rb
@@ -2,23 +2,67 @@
 
 class AppSignUpService < BaseService
   def call(app, remote_ip, params)
-    return unless allowed_registrations?
+    @app       = app
+    @remote_ip = remote_ip
+    @params    = params
 
-    user_params           = params.slice(:email, :password, :agreement, :locale)
-    account_params        = params.slice(:username)
-    invite_request_params = { text: params[:reason] }
-    user                  = User.create!(user_params.merge(created_by_application: app, sign_up_ip: remote_ip, password_confirmation: user_params[:password], account_attributes: account_params, invite_request_attributes: invite_request_params))
+    raise Mastodon::NotPermittedError unless allowed_registrations?
 
-    Doorkeeper::AccessToken.create!(application: app,
-                                    resource_owner_id: user.id,
-                                    scopes: app.scopes,
-                                    expires_in: Doorkeeper.configuration.access_token_expires_in,
-                                    use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?)
+    ApplicationRecord.transaction do
+      create_user!
+      create_access_token!
+    end
+
+    @access_token
   end
 
   private
 
+  def create_user!
+    @user = User.create!(
+      user_params.merge(created_by_application: @app, sign_up_ip: @remote_ip, password_confirmation: user_params[:password], account_attributes: account_params, invite_request_attributes: invite_request_params)
+    )
+  end
+
+  def create_access_token!
+    @access_token = Doorkeeper::AccessToken.create!(
+      application: @app,
+      resource_owner_id: @user.id,
+      scopes: @app.scopes,
+      expires_in: Doorkeeper.configuration.access_token_expires_in,
+      use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
+    )
+  end
+
+  def user_params
+    @params.slice(:email, :password, :agreement, :locale)
+  end
+
+  def account_params
+    @params.slice(:username)
+  end
+
+  def invite_request_params
+    { text: @params[:reason] }
+  end
+
   def allowed_registrations?
-    Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode
+    registrations_open? && !single_user_mode? && !omniauth_only? && !ip_blocked?
+  end
+
+  def registrations_open?
+    Setting.registrations_mode != 'none'
+  end
+
+  def single_user_mode?
+    Rails.configuration.x.single_user_mode
+  end
+
+  def omniauth_only?
+    ENV['OMNIAUTH_ONLY'] == 'true'
+  end
+
+  def ip_blocked?
+    IpBlock.where(severity: :sign_up_block).where('ip >>= ?', @remote_ip.to_s).exists?
   end
 end
diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml
index 84040e480..e0879fcb6 100644
--- a/app/views/admin/accounts/index.html.haml
+++ b/app/views/admin/accounts/index.html.haml
@@ -18,7 +18,7 @@
     .filter-subset.filter-subset--with-select
       %strong= t 'generic.order_by'
       .input.select
-        = select_tag :order, options_for_select([[t('relationships.most_recent'), nil], [t('relationships.last_active'), 'active']], params[:order])
+        = select_tag :order, options_for_select([[t('relationships.most_recent'), 'recent'], [t('relationships.last_active'), 'active']], params[:order])
 
   .fields-group
     - %i(username by_domain display_name email ip).each do |key|
diff --git a/app/views/admin/roles/_form.html.haml b/app/views/admin/roles/_form.html.haml
index 9beaf619f..31f78f240 100644
--- a/app/views/admin/roles/_form.html.haml
+++ b/app/views/admin/roles/_form.html.haml
@@ -13,7 +13,7 @@
         = f.input :position, wrapper: :with_label, input_html: { max: current_user.role.position - 1 }
 
     .fields-group
-      = f.input :color, wrapper: :with_label, input_html: { placeholder: '#000000' }
+      = f.input :color, wrapper: :with_label, input_html: { placeholder: '#000000', type: 'color' }
 
     %hr.spacer/
 
diff --git a/app/views/filters/_filter.html.haml b/app/views/filters/_filter.html.haml
index 2ab014081..9993ad2ee 100644
--- a/app/views/filters/_filter.html.haml
+++ b/app/views/filters/_filter.html.haml
@@ -22,6 +22,15 @@
               - keywords = filter.keywords.map(&:keyword)
               - keywords = keywords.take(5) + ['…'] if keywords.size > 5 # TODO
               = keywords.join(', ')
+      - unless filter.statuses.empty?
+        %li.permissions-list__item
+          .permissions-list__item__icon
+            = fa_icon('comment')
+          .permissions-list__item__text
+            .permissions-list__item__text__title
+              = t('filters.index.statuses', count: filter.statuses.size)
+            .permissions-list__item__text__type
+              = t('filters.index.statuses_long', count: filter.statuses.size)
 
   .announcements-list__item__action-bar
     .announcements-list__item__meta
diff --git a/app/views/filters/_filter_fields.html.haml b/app/views/filters/_filter_fields.html.haml
index 1a52faa7a..c58978f5a 100644
--- a/app/views/filters/_filter_fields.html.haml
+++ b/app/views/filters/_filter_fields.html.haml
@@ -14,6 +14,13 @@
 
 %hr.spacer/
 
+- unless f.object.statuses.empty?
+  %h4= t('filters.edit.statuses')
+
+  %p.muted-hint= t('filters.edit.statuses_hint_html', path: filter_statuses_path(f.object))
+
+  %hr.spacer/
+
 %h4= t('filters.edit.keywords')
 
 .table-wrapper
diff --git a/app/views/filters/statuses/_status_filter.html.haml b/app/views/filters/statuses/_status_filter.html.haml
new file mode 100644
index 000000000..ba1170cf9
--- /dev/null
+++ b/app/views/filters/statuses/_status_filter.html.haml
@@ -0,0 +1,37 @@
+- status = status_filter.status.proper
+
+.batch-table__row
+  %label.batch-table__row__select.batch-checkbox
+    = f.check_box :status_filter_ids, { multiple: true, include_hidden: false }, status_filter.id
+  .batch-table__row__content
+    .status__content><
+      - if status.spoiler_text.blank?
+        = prerender_custom_emojis(status_content_format(status), status.emojis)
+      - else
+        %details<
+          %summary><
+            %strong> Content warning: #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)}
+          = prerender_custom_emojis(status_content_format(status), status.emojis)
+
+    - status.ordered_media_attachments.each do |media_attachment|
+      %abbr{ title: media_attachment.description }
+        = fa_icon 'link'
+        = media_attachment.file_file_name
+
+    .detailed-status__meta
+      = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'name-tag', target: '_blank', rel: 'noopener noreferrer' do
+        = image_tag(status.account.avatar.url, width: 15, height: 15, alt: display_name(status.account), class: 'avatar')
+        .username= status.account.acct
+      ·
+      = link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener noreferrer' do
+        %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
+      - if status.edited?
+        ·
+        = t('statuses.edited_at_html', date: content_tag(:time, l(status.edited_at), datetime: status.edited_at.iso8601, title: l(status.edited_at), class: 'formatted'))
+      ·
+      = fa_visibility_icon(status)
+      = t("statuses.visibilities.#{status.visibility}")
+      - if status.sensitive?
+        ·
+        = fa_icon('eye-slash fw')
+        = t('stream_entries.sensitive_content')
diff --git a/app/views/filters/statuses/index.html.haml b/app/views/filters/statuses/index.html.haml
new file mode 100644
index 000000000..886de58fa
--- /dev/null
+++ b/app/views/filters/statuses/index.html.haml
@@ -0,0 +1,38 @@
+- content_for :header_tags do
+  = javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous'
+
+- content_for :page_title do
+  = t('filters.statuses.index.title')
+  \-
+  = @filter.title
+
+.filters
+  .back-link
+    = link_to edit_filter_path(@filter) do
+      = fa_icon 'chevron-left fw'
+      = t('filters.statuses.back_to_filter')
+
+%p.hint= t('filters.statuses.index.hint')
+
+%hr.spacer/
+
+= form_for(@status_filter_batch_action, url: batch_filter_statuses_path(@filter.id)) do |f|
+  = hidden_field_tag :page, params[:page] || 1
+
+  - Admin::StatusFilter::KEYS.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
+        - unless @status_filters.empty?
+          = f.button safe_join([fa_icon('times'), t('filters.statuses.batch.remove')]), name: :remove, class: 'table-action-link', type: :submit
+    .batch-table__body
+      - if @status_filters.empty?
+        = nothing_here 'nothing-here--under-tabs'
+      - else
+        = render partial: 'status_filter', collection: @status_filters, locals: { f: f }
+
+= paginate @status_filters
diff --git a/boxfile.yml b/boxfile.yml
deleted file mode 100644
index 27166cec9..000000000
--- a/boxfile.yml
+++ /dev/null
@@ -1,205 +0,0 @@
-run.config:
-  engine: ruby
-  engine.config:
-    runtime: ruby-2.5
-
-  extra_packages:
-    # basic servers:
-    - nginx
-    - nodejs
-
-    # for images:
-    - ImageMagick
-    - jemalloc
-
-    # for videos:
-    - ffmpeg3
-
-    # to prep the .env file:
-    - gettext-tools
-
-    # for node-gyp, used in the asset compilation process:
-    - python-2
-
-    # i18n:
-    - libidn
-
-  cache_dirs:
-    - node_modules
-
-  extra_path_dirs:
-    - node_modules/.bin
-
-  build_triggers:
-    - .ruby-version
-    - Gemfile
-    - Gemfile.lock
-    - package.json
-    - yarn.lock
-
-  extra_steps:
-    - cp .env.nanobox .env
-    - yarn
-
-  fs_watch: true
-
-deploy.config:
-  extra_steps:
-    - NODE_ENV=production bundle exec rake assets:precompile
-  transform:
-    - 'envsubst < /app/.env.nanobox > /app/.env.production'
-    - |-
-      if [ -z "$LOCAL_DOMAIN" ]
-      then
-        . /app/.env.production
-        export LOCAL_DOMAIN
-      fi
-      erb /app/nanobox/nginx-web.conf.erb > /app/nanobox/nginx-web.conf
-      erb /app/nanobox/nginx-stream.conf.erb > /app/nanobox/nginx-stream.conf
-    - touch /app/log/production.log
-  before_live:
-    web.web:
-      - bin/tootctl cache clear
-      - bundle exec rake db:migrate:setup
-  after_live:
-    worker.sidekiq:
-      - |-
-        if [[ "${ES_ENABLED}" != "false" ]]
-        then
-          bin/tootctl search deploy
-        fi
-
-web.web:
-  start:
-    nginx: nginx -c /app/nanobox/nginx-web.conf
-    rails: bundle exec puma -C /app/config/puma.rb
-
-  routes:
-    - '/'
-
-  writable_dirs:
-    - tmp
-
-  log_watch:
-    rails: 'log/production.log'
-
-  network_dirs:
-    data.storage:
-      - public/system
-
-web.stream:
-  start:
-    nginx: nginx -c /app/nanobox/nginx-stream.conf
-    node: yarn run start
-
-  routes:
-    - '/api/v1/streaming*'
-    # Somehow we're getting requests for scheme://domain//api/v1/streaming* - match those, too
-    - '//api/v1/streaming*'
-
-  writable_dirs:
-    - tmp
-
-worker.sidekiq:
-  start:
-    default: bundle exec sidekiq -c 5 -q default -L /app/log/sidekiq.log
-    mailers: bundle exec sidekiq -c 5 -q mailers -L /app/log/sidekiq.log
-    pull: bundle exec sidekiq -c 5 -q pull -L /app/log/sidekiq.log
-    push: bundle exec sidekiq -c 5 -q push -L /app/log/sidekiq.log
-    scheduler: bundle exec sidekiq -c 5 -q scheduler -L /app/log/sidekiq.log
-
-  writable_dirs:
-    - tmp
-
-  log_watch:
-    rails: 'log/production.log'
-    sidekiq: 'log/sidekiq.log'
-
-  network_dirs:
-    data.storage:
-      - public/system
-
-data.db:
-  image: nanobox/postgresql:9.6
-
-  cron:
-    - id: backup
-      schedule: '0 3 * * *'
-      command: |
-        PGPASSWORD=${DATA_DB_PASS} pg_dump -U ${DATA_DB_USER} -w -Fc -O gonano |
-        gzip |
-        curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/backup-${HOSTNAME}-$(date -u +%Y-%m-%d.%H-%M-%S).sql.gz -X POST -T - >&2
-        curl -k -s -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/ |
-        sed 's/,/\n/g' |
-        grep ${HOSTNAME} |
-        sort |
-        head -n-${BACKUP_COUNT:-1} |
-        sed 's/.*: \?"\(.*\)".*/\1/' |
-        while read file
-        do
-          curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE
-        done
-
-data.elastic:
-  image: nanobox/elasticsearch:5
-
-  cron:
-    - id: backup
-      schedule: '0 3 * * *'
-      command: |
-        id=$(cat /proc/sys/kernel/random/uuid)
-        curl -X PUT -H "Content-Type: application/json" "127.0.0.1:9200/_snapshot/${id}" -d "{\"type\": \"fs\",\"settings\": {\"location\": \"/var/tmp/${id}\",\"compress\": true}}"
-        curl -X PUT -H "Content-Type: application/json" "127.0.0.1:9200/_snapshot/${id}/backup?wait_for_completion=true&pretty"
-        tar -cz -C "/var/tmp/${id}" . |
-        curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/backup-${HOSTNAME}-$(date -u +%Y-%m-%d.%H-%M-%S).tgz -X POST -T - >&2
-        curl -X DELETE -H "Content-Type: application/json" "127.0.0.1:9200/_snapshot/${id}"
-        rm -rf "/var/tmp/${id}"
-        curl -k -s -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/ |
-        sed 's/,/\n/g' |
-        grep ${HOSTNAME} |
-        sort |
-        head -n-${BACKUP_COUNT:-1} |
-        sed 's/.*: \?"\(.*\)".*/\1/' |
-        while read file
-        do
-          curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE
-        done
-
-data.redis:
-  image: nanobox/redis:4.0
-
-  cron:
-    - id: backup
-      schedule: '0 3 * * *'
-      command: |
-        curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/backup-${HOSTNAME}-$(date -u +%Y-%m-%d.%H-%M-%S).rdb -X POST -T /data/var/db/redis/dump.rdb >&2
-        curl -k -s -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/ |
-        sed 's/,/\n/g' |
-        grep ${HOSTNAME} |
-        sort |
-        head -n-${BACKUP_COUNT:-1} |
-        sed 's/.*: \?"\(.*\)".*/\1/' |
-        while read file
-        do
-          curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE
-        done
-
-data.storage:
-  image: nanobox/unfs:0.9
-
-  cron:
-    - id: backup
-      schedule: '0 3 * * *'
-      command: |
-        tar cz -C /data/var/db/unfs/ . |
-        curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/backup-${HOSTNAME}-$(date -u +%Y-%m-%d.%H-%M-%S).tgz -X POST -T - >&2
-        curl -k -s -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/ |
-        sed 's/,/\n/g' |
-        grep ${HOSTNAME} |
-        sort |
-        head -n-${BACKUP_COUNT:-1} |
-        sed 's/.*: \?"\(.*\)".*/\1/' |
-        while read file
-        do
-          curl -k -H "X-AUTH-TOKEN: ${WAREHOUSE_DATA_HOARDER_TOKEN}" https://${WAREHOUSE_DATA_HOARDER_HOST}:7410/blobs/${file} -X DELETE
-        done
diff --git a/chart/.helmignore b/chart/.helmignore
index 0e8a0eb36..886747ed0 100644
--- a/chart/.helmignore
+++ b/chart/.helmignore
@@ -21,3 +21,4 @@
 .idea/
 *.tmproj
 .vscode/
+mastodon-*.tgz
diff --git a/chart/Chart.lock b/chart/Chart.lock
index d74e7570c..961e4fa80 100644
--- a/chart/Chart.lock
+++ b/chart/Chart.lock
@@ -1,12 +1,12 @@
 dependencies:
 - name: elasticsearch
-  repository: https://charts.bitnami.com/bitnami
-  version: 15.10.3
+  repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
+  version: 19.0.1
 - name: postgresql
-  repository: https://charts.bitnami.com/bitnami
-  version: 8.10.14
+  repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
+  version: 11.1.3
 - name: redis
-  repository: https://charts.bitnami.com/bitnami
-  version: 10.9.0
-digest: sha256:f5c57108f7768fd16391c1a050991c7809f84a640cca308d7d24d87379d04000
-generated: "2021-08-05T08:01:01.457727804Z"
+  repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
+  version: 16.13.2
+digest: sha256:17ea58a3264aa22faff18215c4269f47dabae956d0df273c684972f356416193
+generated: "2022-08-08T21:44:18.0195364+02:00"
diff --git a/chart/Chart.yaml b/chart/Chart.yaml
index 1687132ac..b1138b594 100644
--- a/chart/Chart.yaml
+++ b/chart/Chart.yaml
@@ -15,7 +15,7 @@ type: application
 # This is the chart version. This version number should be incremented each time you make changes
 # to the chart and its templates, including the app version.
 # Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 1.2.1
+version: 2.0.0
 
 # This is the version number of the application being deployed. This version number should be
 # incremented each time you make changes to the application. Versions are not expected to
@@ -24,13 +24,13 @@ appVersion: 3.3.0
 
 dependencies:
   - name: elasticsearch
-    version: 15.10.3
-    repository: https://charts.bitnami.com/bitnami
+    version: 19.0.1
+    repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
     condition: elasticsearch.enabled
   - name: postgresql
-    version: 8.10.14
-    repository: https://charts.bitnami.com/bitnami
+    version: 11.1.3
+    repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
     condition: postgresql.enabled
   - name: redis
-    version: 10.9.0
-    repository: https://charts.bitnami.com/bitnami
+    version: 16.13.2
+    repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl
index 5814a3120..71bb002ef 100644
--- a/chart/templates/_helpers.tpl
+++ b/chart/templates/_helpers.tpl
@@ -77,3 +77,53 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this
 {{- define "mastodon.postgresql.fullname" -}}
 {{- printf "%s-%s" .Release.Name "postgresql" | trunc 63 | trimSuffix "-" -}}
 {{- end -}}
+
+{{/*
+Get the mastodon secret.
+*/}}
+{{- define "mastodon.secretName" -}}
+{{- if .Values.mastodon.secrets.existingSecret }}
+    {{- printf "%s" (tpl .Values.mastodon.secrets.existingSecret $) -}}
+{{- else -}}
+    {{- printf "%s" (include "common.names.fullname" .) -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Get the postgresql secret.
+*/}}
+{{- define "mastodon.postgresql.secretName" -}}
+{{- if (and (or .Values.postgresql.enabled .Values.postgresql.postgresqlHostname) .Values.postgresql.auth.existingSecret) }}
+    {{- printf "%s" (tpl .Values.postgresql.auth.existingSecret $) -}}
+{{- else if .Values.postgresql.enabled -}}
+    {{- printf "%s-postgresql" (tpl .Release.Name $) -}}
+{{- else -}}
+    {{- printf "%s" (include "common.names.fullname" .) -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Get the redis secret.
+*/}}
+{{- define "mastodon.redis.secretName" -}}
+{{- if .Values.redis.auth.existingSecret }}
+    {{- printf "%s" (tpl .Values.redis.auth.existingSecret $) -}}
+{{- else if .Values.redis.existingSecret }}
+    {{- printf "%s" (tpl .Values.redis.existingSecret $) -}}
+{{- else -}}
+    {{- printf "%s-redis" (tpl .Release.Name $) -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Return true if a mastodon secret object should be created
+*/}}
+{{- define "mastodon.createSecret" -}}
+{{- if (or
+    (and .Values.mastodon.s3.enabled (not .Values.mastodon.s3.existingSecret))
+    (not .Values.mastodon.secrets.existingSecret )
+    (and (not .Values.postgresql.enabled) (not .Values.postgresql.auth.existingSecret))
+    ) -}}
+    {{- true -}}
+{{- end -}}
+{{- end -}}
diff --git a/chart/templates/configmap-env.yaml b/chart/templates/configmap-env.yaml
index aa242684f..f988477d9 100644
--- a/chart/templates/configmap-env.yaml
+++ b/chart/templates/configmap-env.yaml
@@ -10,14 +10,14 @@ data:
   {{- else }}
   DB_HOST: {{ .Values.postgresql.postgresqlHostname }}
   {{- end }}
-  DB_NAME: {{ .Values.postgresql.postgresqlDatabase }}
+  DB_NAME: {{ .Values.postgresql.auth.database }}
   DB_POOL: {{ .Values.mastodon.sidekiq.concurrency | quote }}
   DB_PORT: "5432"
-  DB_USER: {{ .Values.postgresql.postgresqlUsername }}
+  DB_USER: {{ .Values.postgresql.auth.username }}
   DEFAULT_LOCALE: {{ .Values.mastodon.locale }}
   {{- if .Values.elasticsearch.enabled }}
   ES_ENABLED: "true"
-  ES_HOST: {{ template "mastodon.elasticsearch.fullname" . }}-master
+  ES_HOST: {{ template "mastodon.elasticsearch.fullname" . }}-master-hl
   ES_PORT: "9200"
   {{- end }}
   LOCAL_DOMAIN: {{ .Values.mastodon.local_domain }}
diff --git a/chart/templates/cronjob-media-remove.yaml b/chart/templates/cronjob-media-remove.yaml
index 3d6e25cc6..160aee204 100644
--- a/chart/templates/cronjob-media-remove.yaml
+++ b/chart/templates/cronjob-media-remove.yaml
@@ -1,5 +1,5 @@
 {{ if .Values.mastodon.cron.removeMedia.enabled }}
-apiVersion: batch/v1beta1
+apiVersion: batch/v1
 kind: CronJob
 metadata:
   name: {{ include "mastodon.fullname" . }}-media-remove
@@ -12,6 +12,10 @@ spec:
       template:
         metadata:
           name: {{ include "mastodon.fullname" . }}-media-remove
+        {{- with .Values.jobAnnotations }}
+          annotations:
+            {{- toYaml . | nindent 12 }}
+        {{- end }}
         spec:
           restartPolicy: OnFailure
           {{- if (not .Values.mastodon.s3.enabled) }}
@@ -49,21 +53,17 @@ spec:
                 - configMapRef:
                     name: {{ include "mastodon.fullname" . }}-env
                 - secretRef:
-                    name: {{ template "mastodon.fullname" . }}
+                    name: {{ template "mastodon.secretName" . }}
               env:
                 - name: "DB_PASS"
                   valueFrom:
                     secretKeyRef:
-                      {{- if .Values.postgresql.enabled }}
-                      name: {{ .Release.Name }}-postgresql
-                      {{- else }}
-                      name: {{ template "mastodon.fullname" . }}
-                      {{- end }}
-                      key: postgresql-password
+                      name: {{ template "mastodon.postgresql.secretName" . }}
+                      key: password
                 - name: "REDIS_PASSWORD"
                   valueFrom:
                     secretKeyRef:
-                      name: {{ .Release.Name }}-redis
+                      name: {{ template "mastodon.redis.secretName" . }}
                       key: redis-password
                 - name: "PORT"
                   value: {{ .Values.mastodon.web.port | quote }}
diff --git a/chart/templates/deployment-sidekiq.yaml b/chart/templates/deployment-sidekiq.yaml
index baf6c2b2d..f1809bd85 100644
--- a/chart/templates/deployment-sidekiq.yaml
+++ b/chart/templates/deployment-sidekiq.yaml
@@ -70,22 +70,31 @@ spec:
             - configMapRef:
                 name: {{ include "mastodon.fullname" . }}-env
             - secretRef:
-                name: {{ template "mastodon.fullname" . }}
+                name: {{ template "mastodon.secretName" . }}
           env:
             - name: "DB_PASS"
               valueFrom:
                 secretKeyRef:
-                  {{- if .Values.postgresql.enabled }}
-                  name: {{ .Release.Name }}-postgresql
-                  {{- else }}
-                  name: {{ template "mastodon.fullname" . }}
-                  {{- end }}
-                  key: postgresql-password
+                  name: {{ template "mastodon.postgresql.secretName" . }}
+                  key: password
             - name: "REDIS_PASSWORD"
               valueFrom:
                 secretKeyRef:
-                  name: {{ .Release.Name }}-redis
+                  name: {{ template "mastodon.redis.secretName" . }}
                   key: redis-password
+            {{- if .Values.mastodon.smtp.existingSecret }}
+            - name: "SMTP_LOGIN"
+              valueFrom:
+                secretKeyRef:
+                  name: {{ .Values.mastodon.smtp.existingSecret }}
+                  key: login
+                  optional: true
+            - name: "SMTP_PASSWORD"
+              valueFrom:
+                secretKeyRef:
+                  name: {{ .Values.mastodon.smtp.existingSecret }}
+                  key: password
+            {{- end -}}
           {{- if (not .Values.mastodon.s3.enabled) }}
           volumeMounts:
             - name: assets
diff --git a/chart/templates/deployment-streaming.yaml b/chart/templates/deployment-streaming.yaml
index b332b686a..12203a530 100644
--- a/chart/templates/deployment-streaming.yaml
+++ b/chart/templates/deployment-streaming.yaml
@@ -43,16 +43,12 @@ spec:
             - name: "DB_PASS"
               valueFrom:
                 secretKeyRef:
-                  {{- if .Values.postgresql.enabled }}
-                  name: {{ .Release.Name }}-postgresql
-                  {{- else }}
-                  name: {{ template "mastodon.fullname" . }}
-                  {{- end }}
-                  key: postgresql-password
+                  name: {{ template "mastodon.postgresql.secretName" . }}
+                  key: password
             - name: "REDIS_PASSWORD"
               valueFrom:
                 secretKeyRef:
-                  name: {{ .Release.Name }}-redis
+                  name: {{ template "mastodon.redis.secretName" . }}
                   key: redis-password
             - name: "PORT"
               value: {{ .Values.mastodon.streaming.port | quote }}
diff --git a/chart/templates/deployment-web.yaml b/chart/templates/deployment-web.yaml
index 8b8bb4f29..ab722c77b 100644
--- a/chart/templates/deployment-web.yaml
+++ b/chart/templates/deployment-web.yaml
@@ -56,24 +56,32 @@ spec:
             - configMapRef:
                 name: {{ include "mastodon.fullname" . }}-env
             - secretRef:
-                name: {{ template "mastodon.fullname" . }}
+                name: {{ template "mastodon.secretName" . }}
           env:
             - name: "DB_PASS"
               valueFrom:
                 secretKeyRef:
-                  {{- if .Values.postgresql.enabled }}
-                  name: {{ .Release.Name }}-postgresql
-                  {{- else }}
-                  name: {{ template "mastodon.fullname" . }}
-                  {{- end }}
-                  key: postgresql-password
+                  name: {{ template "mastodon.postgresql.secretName" . }}
+                  key: password
             - name: "REDIS_PASSWORD"
               valueFrom:
                 secretKeyRef:
-                  name: {{ .Release.Name }}-redis
+                  name: {{ template "mastodon.redis.secretName" . }}
                   key: redis-password
             - name: "PORT"
               value: {{ .Values.mastodon.web.port | quote }}
+            {{- if (and .Values.mastodon.s3.enabled .Values.mastodon.s3.existingSecret) }}
+            - name: "AWS_SECRET_ACCESS_KEY"
+              valueFrom:
+                secretKeyRef:
+                  name: {{ .Values.mastodon.s3.existingSecret }}
+                  key: AWS_SECRET_ACCESS_KEY
+            - name: "AWS_ACCESS_KEY_ID"
+              valueFrom:
+                secretKeyRef:
+                  name: {{ .Values.mastodon.s3.existingSecret }}
+                  key: AWS_ACCESS_KEY_ID
+            {{- end -}}
           {{- if (not .Values.mastodon.s3.enabled) }}
           volumeMounts:
             - name: assets
diff --git a/chart/templates/job-assets-precompile.yaml b/chart/templates/job-assets-precompile.yaml
index 825a7e916..faa51a20d 100644
--- a/chart/templates/job-assets-precompile.yaml
+++ b/chart/templates/job-assets-precompile.yaml
@@ -12,6 +12,10 @@ spec:
   template:
     metadata:
       name: {{ include "mastodon.fullname" . }}-assets-precompile
+    {{- with .Values.jobAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
     spec:
       restartPolicy: Never
       {{- if (not .Values.mastodon.s3.enabled) }}
@@ -50,21 +54,17 @@ spec:
             - configMapRef:
                 name: {{ include "mastodon.fullname" . }}-env
             - secretRef:
-                name: {{ template "mastodon.fullname" . }}
+                name: {{ template "mastodon.secretName" . }}
           env:
             - name: "DB_PASS"
               valueFrom:
                 secretKeyRef:
-                  {{- if .Values.postgresql.enabled }}
-                  name: {{ .Release.Name }}-postgresql
-                  {{- else }}
-                  name: {{ template "mastodon.fullname" . }}
-                  {{- end }}
-                  key: postgresql-password
+                  name: {{ template "mastodon.postgresql.secretName" . }}
+                  key: password
             - name: "REDIS_PASSWORD"
               valueFrom:
                 secretKeyRef:
-                  name: {{ .Release.Name }}-redis
+                  name: {{ template "mastodon.redis.secretName" . }}
                   key: redis-password
             - name: "PORT"
               value: {{ .Values.mastodon.web.port | quote }}
diff --git a/chart/templates/job-chewy-upgrade.yaml b/chart/templates/job-chewy-upgrade.yaml
index cc68a3385..ae6fb38e1 100644
--- a/chart/templates/job-chewy-upgrade.yaml
+++ b/chart/templates/job-chewy-upgrade.yaml
@@ -13,6 +13,10 @@ spec:
   template:
     metadata:
       name: {{ include "mastodon.fullname" . }}-chewy-upgrade
+    {{- with .Values.jobAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
     spec:
       restartPolicy: Never
       {{- if (not .Values.mastodon.s3.enabled) }}
@@ -51,21 +55,17 @@ spec:
             - configMapRef:
                 name: {{ include "mastodon.fullname" . }}-env
             - secretRef:
-                name: {{ template "mastodon.fullname" . }}
+                name: {{ template "mastodon.secretName" . }}
           env:
             - name: "DB_PASS"
               valueFrom:
                 secretKeyRef:
-                  {{- if .Values.postgresql.enabled }}
-                  name: {{ .Release.Name }}-postgresql
-                  {{- else }}
-                  name: {{ template "mastodon.fullname" . }}
-                  {{- end }}
-                  key: postgresql-password
+                  name: {{ template "mastodon.postgresql.secretName" . }}
+                  key: password
             - name: "REDIS_PASSWORD"
               valueFrom:
                 secretKeyRef:
-                  name: {{ .Release.Name }}-redis
+                  name: {{ template "mastodon.redis.secretName" . }}
                   key: redis-password
             - name: "PORT"
               value: {{ .Values.mastodon.web.port | quote }}
diff --git a/chart/templates/job-create-admin.yaml b/chart/templates/job-create-admin.yaml
index ffb8bb059..659c00671 100644
--- a/chart/templates/job-create-admin.yaml
+++ b/chart/templates/job-create-admin.yaml
@@ -13,6 +13,10 @@ spec:
   template:
     metadata:
       name: {{ include "mastodon.fullname" . }}-create-admin
+    {{- with .Values.jobAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
     spec:
       restartPolicy: Never
       {{- if (not .Values.mastodon.s3.enabled) }}
@@ -56,21 +60,17 @@ spec:
             - configMapRef:
                 name: {{ include "mastodon.fullname" . }}-env
             - secretRef:
-                name: {{ template "mastodon.fullname" . }}
+                name: {{ template "mastodon.secretName" . }}
           env:
             - name: "DB_PASS"
               valueFrom:
                 secretKeyRef:
-                  {{- if .Values.postgresql.enabled }}
-                  name: {{ .Release.Name }}-postgresql
-                  {{- else }}
-                  name: {{ template "mastodon.fullname" . }}
-                  {{- end }}
-                  key: postgresql-password
+                  name: {{ template "mastodon.postgresql.secretName" . }}
+                  key: password
             - name: "REDIS_PASSWORD"
               valueFrom:
                 secretKeyRef:
-                  name: {{ .Release.Name }}-redis
+                  name: {{ template "mastodon.redis.secretName" . }}
                   key: redis-password
             - name: "PORT"
               value: {{ .Values.mastodon.web.port | quote }}
diff --git a/chart/templates/job-db-migrate.yaml b/chart/templates/job-db-migrate.yaml
index 72f910e3b..8e4f70dfb 100644
--- a/chart/templates/job-db-migrate.yaml
+++ b/chart/templates/job-db-migrate.yaml
@@ -12,6 +12,10 @@ spec:
   template:
     metadata:
       name: {{ include "mastodon.fullname" . }}-db-migrate
+    {{- with .Values.jobAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
     spec:
       restartPolicy: Never
       {{- if (not .Values.mastodon.s3.enabled) }}
@@ -50,21 +54,17 @@ spec:
             - configMapRef:
                 name: {{ include "mastodon.fullname" . }}-env
             - secretRef:
-                name: {{ template "mastodon.fullname" . }}
+                name: {{ template "mastodon.secretName" . }}
           env:
             - name: "DB_PASS"
               valueFrom:
                 secretKeyRef:
-                  {{- if .Values.postgresql.enabled }}
-                  name: {{ .Release.Name }}-postgresql
-                  {{- else }}
-                  name: {{ template "mastodon.fullname" . }}
-                  {{- end }}
-                  key: postgresql-password
+                  name: {{ template "mastodon.postgresql.secretName" . }}
+                  key: password
             - name: "REDIS_PASSWORD"
               valueFrom:
                 secretKeyRef:
-                  name: {{ .Release.Name }}-redis
+                  name: {{ template "mastodon.redis.secretName" . }}
                   key: redis-password
             - name: "PORT"
               value: {{ .Values.mastodon.web.port | quote }}
diff --git a/chart/templates/secrets.yaml b/chart/templates/secrets.yaml
index 0452a8ae1..135d5b61a 100644
--- a/chart/templates/secrets.yaml
+++ b/chart/templates/secrets.yaml
@@ -1,3 +1,4 @@
+{{- if (include "mastodon.createSecret" .) }}
 apiVersion: v1
 kind: Secret
 metadata:
@@ -7,9 +8,12 @@ metadata:
 type: Opaque
 data:
   {{- if .Values.mastodon.s3.enabled }}
+  {{- if not .Values.mastodon.s3.existingSecret }}
   AWS_ACCESS_KEY_ID: "{{ .Values.mastodon.s3.access_key | b64enc }}"
   AWS_SECRET_ACCESS_KEY: "{{ .Values.mastodon.s3.access_secret | b64enc }}"
   {{- end }}
+  {{- end }}
+  {{- if not .Values.mastodon.secrets.existingSecret }}
   {{- if not (empty .Values.mastodon.secrets.secret_key_base) }}
   SECRET_KEY_BASE: "{{ .Values.mastodon.secrets.secret_key_base | b64enc }}"
   {{- else }}
@@ -30,6 +34,10 @@ data:
   {{- else }}
   VAPID_PUBLIC_KEY: {{ required "vapid.public_key is required" .Values.mastodon.secrets.vapid.public_key }}
   {{- end }}
+  {{- end }}
   {{- if not .Values.postgresql.enabled }}
-  postgresql-password: "{{ .Values.postgresql.postgresqlPassword | b64enc }}"
+  {{- if not .Values.postgresql.auth.existingSecret }}
+  postgresql-password: "{{ .Values.postgresql.auth.password | b64enc }}"
+  {{- end }}
   {{- end }}
+{{- end -}}
diff --git a/chart/values.yaml b/chart/values.yaml
index 2cfa3484b..4b18a9dfa 100644
--- a/chart/values.yaml
+++ b/chart/values.yaml
@@ -48,6 +48,9 @@ mastodon:
     enabled: false
     access_key: ""
     access_secret: ""
+    # you can also specify the name of an existing Secret
+    # with keys AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
+    existingSecret: ""
     bucket: ""
     endpoint: https://us-east-1.linodeobjects.com
     hostname: us-east-1.linodeobjects.com
@@ -61,6 +64,10 @@ mastodon:
     vapid:
       private_key: ""
       public_key: ""
+    # you can also specify the name of an existing Secret
+    # with keys SECRET_KEY_BASE and OTP_SECRET and
+    # VAPID_PRIVATE_KEY and VAPID_PUBLIC_KEY
+    existingSecret: ""
   sidekiq:
     concurrency: 25
   smtp:
@@ -70,13 +77,16 @@ mastodon:
     domain:
     enable_starttls_auto: true
     from_address: notifications@example.com
-    login:
     openssl_verify_mode: peer
-    password:
     port: 587
     reply_to:
     server: smtp.mailgun.org
     tls: false
+    login:
+    password:
+    # you can also specify the name of an existing Secret
+    # with the keys login and password
+    existingSecret:
   streaming:
     port: 4000
     # this should be set manually since os.cpus() returns the number of CPUs on
@@ -127,18 +137,26 @@ postgresql:
   # must match those of that external postgres instance
   enabled: true
   # postgresqlHostname: preexisting-postgresql
-  postgresqlDatabase: mastodon_production
-  # you must set a password; the password generated by the postgresql chart will
-  # be rotated on each upgrade:
-  # https://github.com/bitnami/charts/tree/master/bitnami/postgresql#upgrade
-  postgresqlPassword: ""
-  postgresqlUsername: postgres
+  auth:
+    database: mastodon_production
+    username: postgres
+    # you must set a password; the password generated by the postgresql chart will
+    # be rotated on each upgrade:
+    # https://github.com/bitnami/charts/tree/master/bitnami/postgresql#upgrade
+    password: ""
+    # you can also specify the name of an existing Secret
+    # with a key of postgres-password set to the password you want
+    existingSecret: ""
 
 # https://github.com/bitnami/charts/tree/master/bitnami/redis#parameters
 redis:
   # you must set a password; the password generated by the redis chart will be
   # rotated on each upgrade:
   password: ""
+  # you can also specify the name of an existing Secret
+  # with a key of redis-password set to the password you want
+  # auth:
+    # existingSecret: ""
 
 service:
   type: ClusterIP
@@ -157,45 +175,45 @@ externalAuth:
     # client_secret: SECRETKEY
     # redirect_uri: https://example.com/auth/auth/openid_connect/callback
     # assume_email_is_verified: true
-    # client_auth_method: 
-    # response_type: 
-    # response_mode: 
-    # display: 
-    # prompt: 
-    # send_nonce: 
-    # send_scope_to_token_endpoint: 
-    # idp_logout_redirect_uri: 
-    # http_scheme: 
-    # host: 
-    # port: 
-    # jwks_uri: 
-    # auth_endpoint: 
-    # token_endpoint: 
-    # user_info_endpoint: 
-    # end_session_endpoint: 
+    # client_auth_method:
+    # response_type:
+    # response_mode:
+    # display:
+    # prompt:
+    # send_nonce:
+    # send_scope_to_token_endpoint:
+    # idp_logout_redirect_uri:
+    # http_scheme:
+    # host:
+    # port:
+    # jwks_uri:
+    # auth_endpoint:
+    # token_endpoint:
+    # user_info_endpoint:
+    # end_session_endpoint:
   saml:
     enabled: false
     # acs_url: http://mastodon.example.com/auth/auth/saml/callback
     # issuer: mastodon
     # idp_sso_target_url: https://login.example.com/auth/realms/example/protocol/saml
     # idp_cert: '-----BEGIN CERTIFICATE-----[your_cert_content]-----END CERTIFICATE-----'
-    # idp_cert_fingerprint: 
+    # idp_cert_fingerprint:
     # name_identifier_format: urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
-    # cert: 
-    # private_key: 
+    # cert:
+    # private_key:
     # want_assertion_signed: true
     # want_assertion_encrypted: true
     # assume_email_is_verified: true
     # uid_attribute: "urn:oid:0.9.2342.19200300.100.1.1"
-    # attributes_statements: 
+    # attributes_statements:
     #   uid: "urn:oid:0.9.2342.19200300.100.1.1"
     #   email: "urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
     #   full_name: "urn:oid:2.16.840.1.113730.3.1.241"
     #   first_name: "urn:oid:2.5.4.42"
     #   last_name: "urn:oid:2.5.4.4"
-    #   verified: 
-    #   verified_email: 
-  oauth_global: 
+    #   verified:
+    #   verified_email:
+  oauth_global:
     # Force redirect local login to CAS. Does not function with SAML or LDAP.
     oauth_redirect_at_sign_in: false
   cas:
@@ -204,15 +222,15 @@ externalAuth:
     # host: sso.myserver.com
     # port: 443
     # ssl: true
-    # validate_url: 
-    # callback_url: 
-    # logout_url: 
-    # login_url: 
+    # validate_url:
+    # callback_url:
+    # logout_url:
+    # login_url:
     # uid_field: 'user'
-    # ca_path: 
+    # ca_path:
     # disable_ssl_verification: false
     # assume_email_is_verified: true
-    # keys: 
+    # keys:
     #   uid: 'user'
     #   name: 'name'
     #   email: 'email'
@@ -222,7 +240,7 @@ externalAuth:
     #   location: 'location'
     #   image: 'image'
     #   phone: 'phone'
-  pam: 
+  pam:
     enabled: false
     # email_domain: example.com
     # default_service: rpam
@@ -232,9 +250,9 @@ externalAuth:
     # host: myservice.namespace.svc
     # port: 389
     # method: simple_tls
-    # base: 
-    # bind_on: 
-    # password: 
+    # base:
+    # bind_on:
+    # password:
     # uid: cn
     # mail: mail
     # search_filter: "(|(%{uid}=%{email})(%{mail}=%{email}))"
@@ -263,8 +281,14 @@ serviceAccount:
   # If not set and create is true, a name is generated using the fullname template
   name: ""
 
+# Kubernetes manages pods for jobs and pods for deployments differently, so you might
+# need to apply different annotations to the two different sets of pods. The annotations
+# set with podAnnotations will be added to all deployment-managed pods.
 podAnnotations: {}
 
+# The annotations set with jobAnnotations will be added to all job pods.
+jobAnnotations: {}
+
 resources: {}
   # We usually recommend not to specify default resources and to leave this as a conscious
   # choice for the user. This also increases chances charts run on environments with little
diff --git a/config/application.rb b/config/application.rb
index 32c84d780..048200731 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -169,7 +169,6 @@ module Mastodon
     config.active_job.queue_adapter = :sidekiq
 
     config.middleware.use Rack::Attack
-    config.middleware.use Rack::Deflater
     config.middleware.use Mastodon::RackMiddleware
 
     config.to_prepare do
diff --git a/config/deploy.rb b/config/deploy.rb
index 8a2316b57..2bdb11595 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-lock '3.17.0'
+lock '3.17.1'
 
 set :repo_url, ENV.fetch('REPO', 'https://github.com/mastodon/mastodon.git')
 set :branch, ENV.fetch('BRANCH', 'master')
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 2ff9ec235..d6f967e74 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -47,7 +47,7 @@ Rails.application.configure do
   config.force_ssl = true
   config.ssl_options = {
     redirect: {
-      exclude: -> request { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') }
+      exclude: -> request { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') || request.headers["Host"].end_with?('.i2p') }
     }
   }
 
diff --git a/config/initializers/http_client_proxy.rb b/config/initializers/http_client_proxy.rb
index 7a9b7b86d..b29e9edd7 100644
--- a/config/initializers/http_client_proxy.rb
+++ b/config/initializers/http_client_proxy.rb
@@ -18,5 +18,22 @@ Rails.application.configure do
     }.compact
   end
 
+  if ENV['http_hidden_proxy'].present?
+    proxy = URI.parse(ENV['http_hidden_proxy'])
+
+    raise "Unsupported proxy type: #{proxy.scheme}" unless %w(http https).include? proxy.scheme
+    raise "No proxy host" unless proxy.host
+
+    host = proxy.host
+    host = host[1...-1] if host[0] == '[' # for IPv6 address
+
+    config.x.http_client_hidden_proxy[:proxy] = {
+      proxy_address: host,
+      proxy_port: proxy.port,
+      proxy_username: proxy.user,
+      proxy_password: proxy.password,
+    }.compact
+  end
+
   config.x.access_to_hidden_service = ENV['ALLOW_ACCESS_TO_HIDDEN_SERVICE'] == 'true'
 end
diff --git a/config/locales/activerecord.de.yml b/config/locales/activerecord.de.yml
index a24862a70..d3c013dc0 100644
--- a/config/locales/activerecord.de.yml
+++ b/config/locales/activerecord.de.yml
@@ -38,3 +38,14 @@ de:
             email:
               blocked: verwendet einen nicht erlaubten E-Mail-Anbieter
               unreachable: scheint nicht zu existieren
+            role_id:
+              elevated: Kann nicht höher als Ihre aktuelle Rolle sein
+        user_role:
+          attributes:
+            permissions_as_keys:
+              dangerous: enthalte Berechtigungen, die für die Basisrolle nicht sicher sind
+              elevated: kann keine Berechtigungen enthalten, die deine aktuelle Rolle nicht besitzt
+              own_role: kann nicht mit deiner aktuellen Rolle geändert werden
+            position:
+              elevated: kann nicht höher sein als deine aktuelle Rolle
+              own_role: kann nicht mit deiner aktuellen Rolle geändert werden
diff --git a/config/locales/activerecord.es-MX.yml b/config/locales/activerecord.es-MX.yml
index 37b9b05df..c7283aafd 100644
--- a/config/locales/activerecord.es-MX.yml
+++ b/config/locales/activerecord.es-MX.yml
@@ -45,5 +45,7 @@ es-MX:
             permissions_as_keys:
               dangerous: incluir permisos que no son seguros para el rol base
               elevated: no se pueden incluir permisos que tu rol actual no posea
+              own_role: no se puede cambiar con tu rol actual
             position:
               elevated: no puede ser mayor que tu rol actual
+              own_role: no se puede cambiar con tu rol actual
diff --git a/config/locales/activerecord.fi.yml b/config/locales/activerecord.fi.yml
index 40dd81812..f9798cabe 100644
--- a/config/locales/activerecord.fi.yml
+++ b/config/locales/activerecord.fi.yml
@@ -21,6 +21,14 @@ fi:
             username:
               invalid: saa sisältää vain kirjaimia, numeroita ja alaviivoja
               reserved: on varattu
+        admin/webhook:
+          attributes:
+            url:
+              invalid: ei ole kelvollinen URL
+        doorkeeper/application:
+          attributes:
+            website:
+              invalid: ei ole kelvollinen URL
         status:
           attributes:
             reblog:
@@ -30,3 +38,14 @@ fi:
             email:
               blocked: käyttää kiellettyä sähköpostipalvelun tarjoajaa
               unreachable: ei näytä olevan olemassa
+            role_id:
+              elevated: ei voi olla korkeampi kuin nykyinen roolisi
+        user_role:
+          attributes:
+            permissions_as_keys:
+              dangerous: sisältää oikeudet, jotka eivät ole turvallisia perusroolille
+              elevated: ei voi sisältää oikeuksia, joita nykyisellä roolillasi ei ole
+              own_role: ei voi muuttaa nykyisellä roolillasi
+            position:
+              elevated: ei voi olla korkeampi kuin nykyinen roolisi
+              own_role: ei voi muuttaa nykyisellä roolillasi
diff --git a/config/locales/activerecord.gd.yml b/config/locales/activerecord.gd.yml
index 2920b561e..b210144ef 100644
--- a/config/locales/activerecord.gd.yml
+++ b/config/locales/activerecord.gd.yml
@@ -21,6 +21,14 @@ gd:
             username:
               invalid: "– chan fhaod ach litrichean gun sràcan, àireamhan ’s fo-loidhnichean a bhith ’na bhroinn"
               reserved: "– tha e glèidhte"
+        admin/webhook:
+          attributes:
+            url:
+              invalid: "– chan eil seo ’na URL dligheach"
+        doorkeeper/application:
+          attributes:
+            website:
+              invalid: "– chan eil seo ’na URL dligheach"
         status:
           attributes:
             reblog:
@@ -30,3 +38,14 @@ gd:
             email:
               blocked: "– tha seo a’ chleachdadh solaraiche puist-d nach eil ceadaichte"
               unreachable: "– tha coltas nach eil seo ann"
+            role_id:
+              elevated: "– chan fhaod seo a bhith nas àirde na an dreuchd a th’ agad an-dràsta"
+        user_role:
+          attributes:
+            permissions_as_keys:
+              dangerous: gabh a-staigh na ceadan nach eil sàbhailte dhan bhun-dreuchd
+              elevated: chan urrainn dhut ceadan a ghabhail a-staigh nach eil aig an dreuchd a th’ agad an-dràsta
+              own_role: cha ghabh seo atharrachadh leis an dreuchd a th’ agad an-dràsta
+            position:
+              elevated: chan fhaod seo a bhith nas àirde na an dreuchd a th’ agad an-dràsta
+              own_role: cha ghabh seo atharrachadh leis an dreuchd a th’ agad an-dràsta
diff --git a/config/locales/activerecord.ja.yml b/config/locales/activerecord.ja.yml
index 52b1b37fd..06d63da7a 100644
--- a/config/locales/activerecord.ja.yml
+++ b/config/locales/activerecord.ja.yml
@@ -38,3 +38,9 @@ ja:
             email:
               blocked: は禁止されているメールプロバイダを使用しています
               unreachable: は存在しないようです
+        user_role:
+          attributes:
+            permissions_as_keys:
+              own_role: 現在と同じロールには変更できません
+            position:
+              own_role: 現在と同じロールには変更できません
diff --git a/config/locales/activerecord.ku.yml b/config/locales/activerecord.ku.yml
index ee8d9a8d8..3eec2950c 100644
--- a/config/locales/activerecord.ku.yml
+++ b/config/locales/activerecord.ku.yml
@@ -45,5 +45,7 @@ ku:
             permissions_as_keys:
               dangerous: mafdayînên ku ji bo rola bingehîn ne ewle ne tê de hene
               elevated: di rola te ya heyî de nabe mafdayîn tê de hebin
+              own_role: bi rola te ya heyî nayê guhertin
             position:
               elevated: nabe ku ji rola te ya heyî bilindtir be
+              own_role: bi rola te ya heyî nayê guhertin
diff --git a/config/locales/activerecord.nn.yml b/config/locales/activerecord.nn.yml
index f23f9ae6c..ce37d1856 100644
--- a/config/locales/activerecord.nn.yml
+++ b/config/locales/activerecord.nn.yml
@@ -6,11 +6,12 @@ nn:
         expires_at: Frist
         options: Val
       user:
-        email: E-mail address
+        agreement: Serviceavtale
+        email: Epostadresse
         locale: Område
         password: Passord
       user/account:
-        username: Brukernavn
+        username: Brukarnamn
       user/invite_request:
         text: Grunn
     errors:
@@ -18,9 +19,32 @@ nn:
         account:
           attributes:
             username:
-              invalid: bare bokstaver, tall og understreker
+              invalid: må innehalde kun bokstavar, tal og understrekar
               reserved: er reservert
+        admin/webhook:
+          attributes:
+            url:
+              invalid: er ikkje ein gyldig URL
+        doorkeeper/application:
+          attributes:
+            website:
+              invalid: er ikkje ein gyldig URL
         status:
           attributes:
             reblog:
-              taken: av status eksisterer allerede
+              taken: av innlegg eksisterer allereie
+        user:
+          attributes:
+            email:
+              unreachable: ser ikkje ut til å eksistere
+            role_id:
+              elevated: kan ikkje vere høgare enn di noverande rolle
+        user_role:
+          attributes:
+            permissions_as_keys:
+              dangerous: inkluder tillatingar som ikkje er trygge for basisrolla
+              elevated: kan ikkje inkludere rettigheiter di noverande rolle ikkje innehar
+              own_role: kan ikkje endrast med di noverande rolle
+            position:
+              elevated: kan ikkje vere høgare enn di noverande rolle
+              own_role: kan ikkje endrast med di noverande rolle
diff --git a/config/locales/da.yml b/config/locales/da.yml
index a08748deb..9538186c4 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -1180,6 +1180,8 @@ da:
     edit:
       add_keyword: Tilføj nøgleord
       keywords: Nøgleord
+      statuses: Individuelle indlæg
+      statuses_hint_html: Dette filter gælder for udvalgte, individuelle indlæg, uanset om de matcher nøgleordene nedenfor. Disse indlæg kan gennemgås og fjernes fra filteret ved at <a href="%{path}">klikke hér</a>.
       title: Redigere filter
     errors:
       deprecated_api_multiple_keywords: Disse parametre kan ikke ændres fra denne applikation, da de gælder for flere end ét filternøgleord. Brug en nyere applikation eller webgrænsefladen.
@@ -1193,10 +1195,23 @@ da:
       keywords:
         one: "%{count} nøgleord"
         other: "%{count} nøgleord"
+      statuses:
+        one: "%{count} indlæg"
+        other: "%{count} indlæg"
+      statuses_long:
+        one: "%{count} individuelt indlæg skjult"
+        other: "%{count} individuelle indlæg skjult"
       title: Filtre
     new:
       save: Gem nye filter
       title: Tilføj nyt filter
+    statuses:
+      back_to_filter: Returnér til filter
+      batch:
+        remove: Fjern fra filter
+      index:
+        hint: Dette filter gælder for udvalgte, individuelle indlæg uanset andre kriterier. Flere indlæg kan føjes til filteret via webgrænsefladen.
+        title: Filtrerede indlæg
   footer:
     developers: Udviklere
     more: Mere…
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 0c8321295..0ce9c3254 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -103,11 +103,17 @@ de:
       avatar: Profilbild
       by_domain: Domain
       change_email:
+        changed_msg: E-Mail erfolgreich geändert!
         current_email: Aktuelle E-Mail-Adresse
         label: E-Mail-Adresse ändern
         new_email: Neue E-Mail-Adresse
         submit: E-Mail-Adresse ändern
         title: E-Mail-Adresse für %{username} ändern
+      change_role:
+        changed_msg: Rolle erfolgreich geändert!
+        label: Rolle ändern
+        no_role: Keine Rolle
+        title: Rolle für %{username} ändern
       confirm: Bestätigen
       confirmed: Bestätigt
       confirming: Bestätigung
@@ -151,6 +157,7 @@ de:
         active: Aktiv
         all: Alle
         pending: In Warteschlange
+        silenced: Limitiert
         suspended: Gesperrt
         title: Moderation
       moderation_notes: Moderationsnotizen
@@ -158,6 +165,7 @@ de:
       most_recent_ip: Letzte IP-Adresse
       no_account_selected: Keine Konten wurden geändert, da keine ausgewählt wurden
       no_limits_imposed: Keine Beschränkungen
+      no_role_assigned: Keine Rolle zugewiesen
       not_subscribed: Nicht abonniert
       pending: In Warteschlange
       perform_full_suspension: Verbannen
@@ -184,6 +192,7 @@ de:
       reset: Zurücksetzen
       reset_password: Passwort zurücksetzen
       resubscribe: Wieder abonnieren
+      role: Rolle
       search: Suche
       search_same_email_domain: Andere Benutzer mit der gleichen E-Mail-Domain
       search_same_ip: Andere Benutzer mit derselben IP
@@ -640,6 +649,67 @@ de:
       unresolved: Ungelöst
       updated_at: Aktualisiert
       view_profile: Zeige Profil
+    roles:
+      add_new: Rolle hinzufügen
+      assigned_users:
+        one: "%{count} Benutzer"
+        other: "%{count} Benutzer"
+      categories:
+        administration: Administration
+        devops: DevOps
+        invites: Einladungen
+        moderation: Moderation
+        special: Spezial
+      delete: Löschen
+      description_html: Mit <strong>Benutzerrollen</strong>können Sie die Funktionen und Bereiche von Mastodon anpassen, auf die Ihre Benutzer zugreifen können.
+      edit: "'%{name}' Rolle bearbeiten"
+      everyone: Standardberechtigungen
+      everyone_full_description_html: Das ist die <strong>-Basis-Rolle</strong> die <strong>jeden Benutzer</strong> betrifft, auch diejenigen ohne zugewiesene Rolle. Alle anderen Rollen erben Berechtigungen davon.
+      permissions_count:
+        one: "%{count} Berechtigung"
+        other: "%{count} Berechtigungen"
+      privileges:
+        administrator: Administrator
+        administrator_description: Benutzer mit dieser Berechtigung werden jede Berechtigung umgehen
+        delete_user_data: Benutzerdaten löschen
+        delete_user_data_description: Erlaubt Benutzern, die Daten anderer Benutzer ohne Verzögerung zu löschen
+        invite_users: Benutzer einladen
+        invite_users_description: Erlaubt Benutzern neue Leute zum Server einzuladen
+        manage_announcements: Ankündigungen verwalten
+        manage_announcements_description: Erlaubt Benutzern Ankündigungen auf dem Server zu verwalten
+        manage_appeals: Anträge verwalten
+        manage_appeals_description: Erlaubt es Benutzer Anträge gegen Moderationsaktionen zu überprüfen
+        manage_blocks: Geblocktes verwalten
+        manage_blocks_description: Erlaubt Benutzern E-Mail-Anbieter und IP-Adressen zu blockieren
+        manage_custom_emojis: Benutzerdefinierte Emojis verwalten
+        manage_custom_emojis_description: Erlaubt Benutzern benutzerdefinierte Emojis auf dem Server zu verwalten
+        manage_federation: Föderation verwalten
+        manage_federation_description: Erlaubt Benutzern, Föderation mit anderen Domänen zu blockieren oder zuzulassen und die Zustellbarkeit zu kontrollieren
+        manage_invites: Einladungen verwalten
+        manage_invites_description: Erlaubt Benutzern Einladungslinks zu durchsuchen und zu deaktivieren
+        manage_reports: Meldungen verwalten
+        manage_reports_description: Erlaubt Benutzern Meldungen zu überprüfen und Moderationsaktionen gegen sie durchzuführen
+        manage_roles: Rollen verwalten
+        manage_roles_description: Erlaubt Benutzern Rollen unter ihren Rollen zu verwalten und zuzuweisen
+        manage_rules: Regeln verwalten
+        manage_rules_description: Erlaubt Benutzern Serverregeln zu ändern
+        manage_settings: Einstellungen verwalten
+        manage_settings_description: Erlaubt Benutzern Site-Einstellungen zu ändern
+        manage_taxonomies: Taxonomien verwalten
+        manage_taxonomies_description: Ermöglicht Benutzern die Überprüfung angesagter Inhalte und das Aktualisieren der Hashtag-Einstellungen
+        manage_user_access: Benutzerzugriff verwalten
+        manage_user_access_description: Erlaubt Benutzern die Zwei-Faktor-Authentifizierung anderer Benutzer zu deaktivieren, ihre E-Mail-Adresse zu ändern und ihr Passwort zurückzusetzen
+        manage_users: Benutzer verwalten
+        manage_users_description: Erlaubt Benutzern die Details anderer Benutzer anzuzeigen und Moderationsaktionen gegen sie auszuführen
+        manage_webhooks: Webhooks verwalten
+        manage_webhooks_description: Erlaubt Benutzern Webhooks für administrative Ereignisse einzurichten
+        view_audit_log: Audit-Log anzeigen
+        view_audit_log_description: Erlaubt Benutzern den Verlauf von administrativen Aktionen auf dem Server zu sehen
+        view_dashboard: Dashboard anzeigen
+        view_dashboard_description: Erlaubt Benutzern den Zugriff auf das Dashboard und verschiedene Metriken
+        view_devops: DevOps
+        view_devops_description: Erlaubt Benutzern auf Sidekiq und pgHero Dashboards zuzugreifen
+      title: Rollen
     rules:
       add_new: Regel hinzufügen
       delete: Löschen
@@ -1109,14 +1179,24 @@ de:
       public: Öffentliche Zeitleisten
       thread: Gespräche
     edit:
+      add_keyword: Stichwort hinzufügen
+      keywords: Stichwörter
       title: Filter bearbeiten
     errors:
+      deprecated_api_multiple_keywords: Diese Parameter können von dieser Anwendung nicht geändert werden, da sie auf mehr als ein Filterschlüsselwort angewendet werden. Verwenden Sie eine neuere Anwendung oder die Web-Schnittstelle.
       invalid_context: Ungültiger oder fehlender Kontext übergeben
     index:
+      contexts: Filter in %{contexts}
       delete: Löschen
       empty: Du hast keine Filter.
+      expires_in: Läuft ab in %{distance}
+      expires_on: Läuft am %{date} ab
+      keywords:
+        one: "%{count} Stichwort"
+        other: "%{count} Stichwörter"
       title: Filter
     new:
+      save: Neuen Filter speichern
       title: Neuen Filter hinzufügen
   footer:
     developers: Entwickler
@@ -1235,6 +1315,8 @@ de:
     copy_account_note_text: 'Dieser Benutzer ist von %{acct} umgezogen, hier waren deine letzten Notizen zu diesem Benutzer:'
   notification_mailer:
     admin:
+      report:
+        subject: "%{name} hat eine Meldung eingereicht"
       sign_up:
         subject: "%{name} registrierte sich"
     digest:
diff --git a/config/locales/devise.en-GB.yml b/config/locales/devise.en-GB.yml
new file mode 100644
index 000000000..ef03d1810
--- /dev/null
+++ b/config/locales/devise.en-GB.yml
@@ -0,0 +1 @@
+en-GB:
diff --git a/config/locales/devise.ku.yml b/config/locales/devise.ku.yml
index 18187a156..d5d0105ef 100644
--- a/config/locales/devise.ku.yml
+++ b/config/locales/devise.ku.yml
@@ -29,13 +29,13 @@ ku:
         title: Navnîşana e-nameyê piştrast bike
       email_changed:
         explanation: 'Navnîşana e-nameyê ajimêra te hate guhertin bo:'
-        extra: Heke te ajimêra xwe ne guhertiye. Ew tê wateya ku kesek ketiye ajimêrê te. Jkx pêborîna xwe zû biguherîne an jî bi rêveberiya rajekar re têkeve têkiliyê heke tu êdî nikare ajimêra xwe bi kar bînî.
+        extra: Ku te ajimêra xwe neguhertiye. Ew tê wateya ku kesek ketiye ajimêrê te. Jkx pêborîna xwe zû biguherîne an jî bi rêveberiya rajekar re têkeve têkiliyê heke tu êdî nikare ajimêra xwe bi kar bînî.
         subject: 'Mastodon: E-name hate guhertin'
         title: Navnîşana e-nameya nû
       password_change:
         explanation: Borînpeyva ajimêra te hate guhertin.
-        extra: Heke te ajimêra xwe ne guhertiye. Ew tê wateya ku kesek ketiye ajimêrê te. Jkx pêborîna xwe zû biguherîne an jî bi rêveberiya rajekar re têkeve têkiliyê heke tu êdî nikare ajimêra xwe bi kar bînî.
-        subject: 'Mastodon: pêborîn hate guhertin'
+        extra: Ku te ajimêra xwe neguhertiye. Ew tê wateya ku kesek ketiye ajimêrê te. Jkx pêborîna xwe zû biguherîne an jî bi rêveberiya rajekar re têkeve têkiliyê heke tu êdî nikare ajimêra xwe bi kar bînî.
+        subject: 'Mastodon: Borînpeyv hate guhertin'
         title: Borînpeyv hate guhertin
       reconfirmation_instructions:
         explanation: Navnîşana nû piştrast bike da ku tu e-nameya xwe biguherînî.
diff --git a/config/locales/devise.nl.yml b/config/locales/devise.nl.yml
index 2cbbee6cf..477c7d41f 100644
--- a/config/locales/devise.nl.yml
+++ b/config/locales/devise.nl.yml
@@ -51,7 +51,7 @@ nl:
         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 toegangscode nodig.
+        explanation: Tweestapsverificatie voor jouw account is ingeschakeld. Om te kunnen inloggen is een door een tweestapsverificatie-app genereerde toegangscode nodig.
         subject: 'Mastodon: Tweestapsverificatie ingeschakeld'
         title: Tweestapsverificatie ingeschakeld
       two_factor_recovery_codes_changed:
diff --git a/config/locales/devise.nn.yml b/config/locales/devise.nn.yml
index 88d8458f7..0318e7ea9 100644
--- a/config/locales/devise.nn.yml
+++ b/config/locales/devise.nn.yml
@@ -41,7 +41,7 @@ nn:
         subject: 'Mastodon: Stadfest e-post for %{instance}'
         title: Stadfest e-postadresse
       reset_password_instructions:
-        action: Endr passord
+        action: Endre passord
         explanation: Du har bedt om eit nytt passord til kontoen din.
         extra: Om du ikkje bad om dette, ignorer denne e-posten. Passordet ditt vert ikkje endra før du går inn på lenkja ovanfor og lagar eit nytt.
         subject: 'Mastodon: Instuksjonar for å endra passord'
@@ -63,51 +63,51 @@ nn:
       webauthn_credential:
         added:
           explanation: Følgende sikkerhetsnøkkel har blitt lagt til i kontoen din
-          subject: 'Mastodon: Ny sikkerhetsnøkkel'
-          title: En ny sikkerhetsnøkkel har blitt lagt til
+          subject: 'Mastodon: Ny sikkerheitsnøkkel'
+          title: Ein ny sikkerheitsnøkkel har blitt lagt til
         deleted:
-          explanation: Følgende sikkerhetsnøkkel har blitt slettet fra kontoen din
-          subject: 'Mastodon: Sikkerhetsnøkkel slettet'
-          title: En av sikkerhetsnøklene dine har blitt slettet
+          explanation: Den følgande sikkerheitsnøkkelen har blitt sletta frå kontoen din
+          subject: 'Mastodon: Sikkerheitsnøkkel sletta'
+          title: Ein av sikkerheitsnøklane dine har blitt sletta
       webauthn_disabled:
-        subject: 'Mastodon: Autentisering med sikkerhetsnøkler ble skrudd av'
-        title: Sikkerhetsnøkler deaktivert
+        subject: 'Mastodon: Autentisering med sikkerheitsnøklar vart skrudd av'
+        title: Sikkerheitsnøklar deaktivert
       webauthn_enabled:
-        subject: 'Mastodon: Sikkerhetsnøkkelsautentisering ble skrudd på'
-        title: Sikkerhetsnøkler aktivert
+        subject: 'Mastodon: Sikkerheitsnøkkelsautentisering vart skrudd på'
+        title: Sikkerheitsnøklar aktivert
     omniauth_callbacks:
-      failure: Du kunne ikkje verte autentisert frå %{kind} av di "%{reason}".
+      failure: Kunne ikkje autentisere deg frå %{kind} fordi "%{reason}".
       success: Autentisert frå %{kind}-konto.
     passwords:
-      no_token: Du har ikkje tilgang til denne sida utan ha gått via ein e-post som gjeld å nullstille passordet. Dersom det er kva du har gjort, dobbelsjekk at du har kopiert heile URLen.
-      send_instructions: Om vi har e-postadressa di i databasen vår, får du ein e-post med lenke til gjenopprette passordet om nokre få minutt. Sjekk søppelpostmappa di om du ikkje fekk denne e-posten.
-      send_paranoid_instructions: Om vi har e-postadressa di i databasen vår, får du ei lenkje til å endra passordet om nokre få minutt. Ver venleg og sjekk søppelpostmappa om du ikkje fekk denne e-posten.
+      no_token: Du har ikkje tilgang til denne sida utan ha gått via ein e-post som gjeld å nullstille passordet. Dersom det var det du gjorde, dobbelsjekk at du har kopiert heile URLen.
+      send_instructions: Om me har epostadressa di i databasen vår, får du ein epost med ei lenke til å gjenopprette passordet om nokre få minutt. Sjekk søppelpostmappa di om du ikkje fekk denne eposten.
+      send_paranoid_instructions: Om me har epostadressa di i databasen vår, får du ei lenke til å endra passordet om nokre få minutt. Ver venleg å sjekke søppelpostmappa om du ikkje fekk denne eposten.
       updated: Passordet ditt er endra. No er du logga inn.
       updated_not_active: Passordet ditt er endra.
     registrations:
-      destroyed: Ha det! Kontoen din er sletta. Vi vonar å sjå deg igjen snart.
+      destroyed: Ha det! Kontoen din er sletta. Me vonar å sjå deg igjen snart.
       signed_up: Velkomen! No er du registrert.
-      signed_up_but_inactive: Du har registrert deg inn, men vi kunne ikkje logga deg inn fordi kontoen din er ikkje aktivert enno.
-      signed_up_but_locked: Du har registrert deg inn, men vi kunne ikkje logga deg inn fordi kontoen din er låst.
-      signed_up_but_pending: Ei melding med ei stadfestingslenkje er vorten send til e-postadressa di. Når du klikkar på lenkja skal vi sjå gjennom søknaden din. Du får ei melding om han vert godkjend.
-      signed_up_but_unconfirmed: Ei melding med ei lenke for å stadfeste kontoen har vorte sendt e-postadressa di. Klikk på lenka for å aktivere kontoen. Sjekk søppelpostmappa dersom du ikkje har fått e-posten.
-      update_needs_confirmation: Du har oppdatert kontoen din, men vi må stadfeste den nye e-postadressa. Sjekk innboksen og følg lenka for å stadfeste adressa di. Sjekk søppelpostmappa dersom du ikkje har fått den e-posten.
+      signed_up_but_inactive: Du har registrert deg, men me kunne ikkje logga deg inn fordi kontoen din er ikkje aktivert enno.
+      signed_up_but_locked: Du har registrert deg, men me kunne ikkje logga deg inn fordi kontoen din er låst.
+      signed_up_but_pending: Ei melding med ei stadfestingslenke har vorte sendt til epostadressa di. Når du klikkar på lenka skal me sjå gjennom søknaden din. Du får ei melding om den vert godkjend.
+      signed_up_but_unconfirmed: Ei melding med ei lenke for å stadfeste kontoen har vorte sendt til epostadressa di. Klikk på lenka for å aktivere kontoen. Sjekk søppelpostmappa dersom du ikkje har fått eposten.
+      update_needs_confirmation: Du har oppdatert kontoen din, men me må stadfesta den nye epostadressa. Sjekk innboksen og fylg lenka for å stadfeste adressa di. Sjekk søppelpostmappa dersom du ikkje har fått denne eposten.
       updated: Kontoen har vorte oppdatert.
     sessions:
       already_signed_out: Logga ut.
       signed_in: Logga inn.
       signed_out: Logga ut.
     unlocks:
-      send_instructions: Om nokre minutt får du ein e-post med instruksjonar for korleis du kan låse opp kontoen din. Sjekk søppelpostmappa om du ikkje finn den mailen.
-      send_paranoid_instructions: Dersom du har konto her, får du ein e-post med instruksjonar for korleis du kan låse opp kontoen din om nokre minutt. Sjekk søppelpostmappa om du ikkje finn den mailen.
+      send_instructions: Om nokre minutt får du ein epost med instruksjonar for korleis du kan låse opp kontoen din. Sjekk søppelpostmappa om du ikkje finn den eposten.
+      send_paranoid_instructions: Dersom du har konto her, får du ein epost med instruksjonar for korleis du kan låse opp kontoen din om nokre minutt. Sjekk søppelpostmappa om du ikkje finn den eposten.
       unlocked: Kontoen din har vorte låst opp. Logg inn for å halde fram.
   errors:
     messages:
-      already_confirmed: er allereie stadfesta, prøv logge inn
+      already_confirmed: er allereie stadfesta, prøv å logge inn
       confirmation_period_expired: må verte stadfesta innan %{period}, spør etter ein ny
-      expired: er utgått, ver venleg å beda om ein ny ein
+      expired: er utgått, ver venleg å be om ein ny ein
       not_found: ikkje funne
       not_locked: var ikkje låst
       not_saved:
         one: '1 feil hindra %{resource} frå verte lagra:'
-        other: "%{count} feil hindra %{resource} frå verte lagra:"
+        other: "%{count} feil hindra %{resource} frå å verte lagra:"
diff --git a/config/locales/devise.tr.yml b/config/locales/devise.tr.yml
index 98baf2916..86b1c951f 100644
--- a/config/locales/devise.tr.yml
+++ b/config/locales/devise.tr.yml
@@ -8,7 +8,7 @@ tr:
     failure:
       already_authenticated: Zaten oturum açtınız.
       inactive: Hesabınız henüz etkinleştirilmedi.
-      invalid: Geçersiz %{authentication_keys} ya da şifre.
+      invalid: Geçersiz %{authentication_keys} ya da parola.
       last_attempt: Hesabınız kilitlenmeden önce bir kez daha denemeniz gerekir.
       locked: Hesabınız kilitlendi.
       not_found_in_database: Geçersiz %{authentication_keys} ya da parola.
@@ -31,7 +31,7 @@ tr:
         subject: 'Mastodon: E-posta adresi değişti'
         title: Yeni e-posta adresi
       password_change:
-        explanation: Hesabınızın şifresi değiştirildi.
+        explanation: Hesabınızın parolası değiştirildi.
         extra: Parolanızı değiştirmediyseniz, büyük olasılıkla birileri hesabınıza erişmiş olabilir. Lütfen derhal parolanızı değiştirin veya hesabınız kilitlendiyse sunucu yöneticisine başvurun.
         subject: 'Mastodon: Parola değiştirildi'
         title: Parola değiştirildi
@@ -81,11 +81,11 @@ tr:
       failure: '%{kind}''den kimliğiniz doğrulanamadı çünkü "%{reason}".'
       success: "%{kind} hesabından başarıyla kimlik doğrulaması yapıldı."
     passwords:
-      no_token: Bu sayfaya şifre sıfırlama e-postasından gelmeden erişemezsiniz. Şifre sıfırlama e-postasından geliyorsanız lütfen sağlanan tam URL'yi kullandığınızdan emin olun.
+      no_token: Bu sayfaya parola sıfırlama e-postasından gelmeden erişemezsiniz. Parola sıfırlama e-postasından geliyorsanız lütfen sağlanan tam URL'yi kullandığınızdan emin olun.
       send_instructions: E-posta adresiniz veritabanımızda varsa, e-posta adresinize birkaç dakika içinde bir parola kurtarma bağlantısı gönderilir. Bu e-postayı almadıysanız, lütfen spam klasörünüzü kontrol edin.
       send_paranoid_instructions: E-posta adresiniz veritabanımızda varsa, e-posta adresinize birkaç dakika içinde bir parola kurtarma bağlantısı gönderilir. Bu e-postayı almadıysanız, lütfen spam klasörünüzü kontrol edin.
-      updated: Şifreniz başarılı bir şekilde değiştirildi. Şu an oturum açtınız.
-      updated_not_active: Şifreniz başarıyla değiştirildi.
+      updated: Parolanız başarılı bir şekilde değiştirildi. Şu an oturum açtınız.
+      updated_not_active: Parolanız başarıyla değiştirildi.
     registrations:
       destroyed: Görüşürüz! hesabın başarıyla iptal edildi. Umarız seni sonra tekrar görürüz.
       signed_up: Hoş geldiniz! Başarılı bir şekilde oturum açtınız.
diff --git a/config/locales/doorkeeper.fi.yml b/config/locales/doorkeeper.fi.yml
index db7c4d01a..5efa63bc9 100644
--- a/config/locales/doorkeeper.fi.yml
+++ b/config/locales/doorkeeper.fi.yml
@@ -60,6 +60,7 @@ fi:
       error:
         title: Tapahtui virhe
       new:
+        prompt_html: "%{client_name} pyytää lupaa käyttää tiliäsi. Se on kolmannen osapuolen sovellus. <strong>Jos et luota siihen, sinun ei pitäisi sallia sitä.</strong>"
         review_permissions: Tarkista käyttöoikeudet
         title: Valtuutus vaaditaan
       show:
@@ -70,6 +71,8 @@ fi:
       confirmations:
         revoke: Oletko varma?
       index:
+        authorized_at: Valtuutettu %{date}
+        description_html: Nämä ovat sovelluksia, jotka voivat käyttää tiliäsi käyttäen API. Jos et tunnista sitä tai sovellus toimii väärin, voit peruuttaa sen käyttöoikeuden.
         last_used_at: Viimeksi käytetty %{date}
         never_used: Ei käytetty
         scopes: Oikeudet
@@ -116,6 +119,9 @@ fi:
         write: Vain kirjoitus
       title:
         accounts: Tilit
+        admin/accounts: Tilien hallinta
+        admin/all: Kaikki hallinnolliset toiminnot
+        admin/reports: Raporttien hallinta
         all: Kaikki
         blocks: Torjutut
         bookmarks: Kirjanmerkit
@@ -147,6 +153,7 @@ fi:
       admin:write: muokata kaikkia tietoja palvelimella
       admin:write:accounts: suorita moderointitoiminnot tileillä
       admin:write:reports: suorita moderointitoiminnot raporteissa
+      crypto: käytä päästä päähän salausta
       follow: seurata, estää, perua eston ja lopettaa tilien seuraaminen
       push: vastaanottaa push-ilmoituksesi
       read: lukea tilin tietoja
@@ -166,6 +173,7 @@ fi:
       write:accounts: muokata profiiliasi
       write:blocks: estää tilit ja palvelimet
       write:bookmarks: kirjanmerkki viestit
+      write:conversations: mykistä ja poistaa keskustelut
       write:favourites: suosikki viestit
       write:filters: luoda suodattimia
       write:follows: seurata ihmisiä
diff --git a/config/locales/doorkeeper.ku.yml b/config/locales/doorkeeper.ku.yml
index f92a228d1..c4e66aef1 100644
--- a/config/locales/doorkeeper.ku.yml
+++ b/config/locales/doorkeeper.ku.yml
@@ -67,7 +67,7 @@ ku:
         title: Destûr hildana vê kodê jê bigire û ji sepanê re pêve bike.
     authorized_applications:
       buttons:
-        revoke: Betal bike
+        revoke: Rake
       confirmations:
         revoke: Ma tu bawerî?
       index:
@@ -149,7 +149,7 @@ ku:
     scopes:
       admin:read: hemû daneyên li ser rajekar bixwîne
       admin:read:accounts: zanyariyên hestiyar yên hemû ajimêran li ser rajekar bixwîne
-      admin:read:reports: zanyariyên hestiyar yên hemû gilîyan û ajimêrên gilêkirî li ser rajekar bixwîne
+      admin:read:reports: zanyariyên hestiyar yên hemû ragihandinan û ajimêrên ragihandî li ser rajekar bixwîne
       admin:write: hemû daneyên li ser rajekar biguherîne
       admin:write:accounts: di ajimêrê de çalakiyên li hev kirî pêk bîne
       admin:write:reports: di ragihandinê de çalakiyên li hev kirî pêk bîne
@@ -181,5 +181,5 @@ ku:
       write:media: pelên medya bar bike
       write:mutes: mirovan û axaftinan bêdeng bike
       write:notifications: agahdariyên xwe pak bike
-      write:reports: mirovên din gilî bike
+      write:reports: mirovên din ragihîne
       write:statuses: şandiyekê biweşîne
diff --git a/config/locales/doorkeeper.nn.yml b/config/locales/doorkeeper.nn.yml
index 789b50f61..d17d38c3f 100644
--- a/config/locales/doorkeeper.nn.yml
+++ b/config/locales/doorkeeper.nn.yml
@@ -60,6 +60,7 @@ nn:
       error:
         title: Ein feil har oppstått
       new:
+        prompt_html: "%{client_name} ønsker tilgang til kontoen din. Det er ein tredjepartsapplikasjon. <strong>Dersom du ikkje stolar på den, bør du ikkje autorisere det.</strong>"
         title: Autorisasjon nødvendig
       show:
         title: Kopier denne autorisasjonskoden og lim den inn i applikasjonen.
@@ -69,6 +70,9 @@ nn:
       confirmations:
         revoke: Er du sikker?
       index:
+        authorized_at: Autorisert den %{date}
+        last_used_at: Sist brukt den %{date}
+        never_used: Aldri brukt
         title: Dine autoriserte applikasjonar
     errors:
       messages:
@@ -104,6 +108,25 @@ nn:
       authorized_applications:
         destroy:
           notice: App avvist.
+    grouped_scopes:
+      title:
+        accounts: Kontoar
+        admin/accounts: Kontoadministrasjon
+        admin/all: Alle administrative funksjonar
+        admin/reports: Rapportadministrasjon
+        all: Alt
+        bookmarks: Bokmerke
+        conversations: Samtalar
+        crypto: Ende-til-ende-kryptering
+        favourites: Favorittar
+        filters: Filter
+        lists: Lister
+        media: Mediavedlegg
+        mutes: Målbindingar
+        notifications: Varsel
+        reports: Rapportar
+        search: Søk
+        statuses: Innlegg
     layouts:
       admin:
         nav:
@@ -118,6 +141,7 @@ nn:
       admin:write: modifisere alle data på tjeneren
       admin:write:accounts: utføre moderatorhandlinger på kontoer
       admin:write:reports: utføre moderatorhandlinger på rapporter
+      crypto: bruk ende-til-ende-kryptering
       follow: følg, blokkér, avblokkér, avfølg brukere
       push: motta dine varsler
       read: lese dine data
@@ -132,12 +156,13 @@ nn:
       read:notifications: sjå varsla dine
       read:reports: sjå rapportane dine
       read:search: søke på dine vegne
-      read:statuses: sjå alle statusar
+      read:statuses: sjå alle innlegg
       write: poste på dine vegne
-      write:accounts: rediger profilen din
+      write:accounts: redigera profilen din
       write:blocks: blokker kontoar og domene
       write:bookmarks: bokmerk statusar
-      write:favourites: merk statusar som favoritt
+      write:conversations: målbind og slett samtalar
+      write:favourites: merk innlegg som favoritt
       write:filters: lag filter
       write:follows: fylg folk
       write:lists: lag lister
@@ -145,4 +170,4 @@ nn:
       write:mutes: målbind folk og samtalar
       write:notifications: tøm varsla dine
       write:reports: rapporter andre folk
-      write:statuses: legg ut statusar
+      write:statuses: publiser innlegg
diff --git a/config/locales/doorkeeper.th.yml b/config/locales/doorkeeper.th.yml
index a7e4a69a5..a0913dc92 100644
--- a/config/locales/doorkeeper.th.yml
+++ b/config/locales/doorkeeper.th.yml
@@ -88,7 +88,7 @@ th:
         invalid_request:
           missing_param: 'พารามิเตอร์ที่จำเป็นขาดหายไป: %{value}'
           request_not_authorized: คำขอจำเป็นต้องได้รับอนุญาต พารามิเตอร์ที่จำเป็นสำหรับการอนุญาตคำขอขาดหายไปหรือไม่ถูกต้อง
-          unknown: คำขอไม่มีพารามิเตอร์ที่จำเป็น รวมค่าพารามิเตอร์ที่ไม่รองรับ หรือผิดรูปแบบ
+          unknown: คำขอไม่มีพารามิเตอร์ที่จำเป็น รวมค่าพารามิเตอร์ที่ไม่รองรับ หรือมิฉะนั้นผิดรูปแบบ
         invalid_resource_owner: ข้อมูลประจำตัวเจ้าของทรัพยากรที่ให้มาไม่ถูกต้อง หรือไม่พบเจ้าของทรัพยากร
         invalid_scope: ขอบเขตที่ขอไม่ถูกต้อง ไม่รู้จัก หรือผิดรูปแบบ
         invalid_token:
diff --git a/config/locales/doorkeeper.tr.yml b/config/locales/doorkeeper.tr.yml
index 351d271d0..51d0dff08 100644
--- a/config/locales/doorkeeper.tr.yml
+++ b/config/locales/doorkeeper.tr.yml
@@ -81,7 +81,7 @@ tr:
     errors:
       messages:
         access_denied: Kaynak sahibi veya yetkilendirme sunucusu isteği reddetti.
-        credential_flow_not_configured: Kaynak Sahibi Şifresi Kimlik Bilgileri akışı Doorkeeper.configure.resource_owner_from_credentials 'ın yapılandırılmamış olması nedeniyle başarısız oldu.
+        credential_flow_not_configured: Kaynak Sahibi Parolası Kimlik Bilgileri akışı Doorkeeper.configure.resource_owner_from_credentials 'ın yapılandırılmamış olması nedeniyle başarısız oldu.
         invalid_client: İstemcinin kimlik doğrulaması bilinmeyen istemci, istemci kimlik doğrulamasının dahil olmaması veya desteklenmeyen kimlik doğrulama yöntemi nedeniyle başarısız oldu.
         invalid_grant: Sağlanan yetkilendirme izni geçersiz, süresi dolmuş, iptal edilmiş, yetkilendirme isteğinde kullanılan yönlendirme URL'siyle eşleşmiyor veya başka bir istemciye verilmiş.
         invalid_redirect_uri: Dahil edilmiş yönlendirme URL'si geçersiz.
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 2cd4f45ac..e495ef841 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1181,6 +1181,8 @@ en:
     edit:
       add_keyword: Add keyword
       keywords: Keywords
+      statuses: Individual posts
+      statuses_hint_html: This filter applies to select individual posts regardless of whether they match the keywords below. <a href="%{path}">Review or remove posts from the filter</a>.
       title: Edit filter
     errors:
       deprecated_api_multiple_keywords: These parameters cannot be changed from this application because they apply to more than one filter keyword. Use a more recent application or the web interface.
@@ -1194,10 +1196,23 @@ en:
       keywords:
         one: "%{count} keyword"
         other: "%{count} keywords"
+      statuses:
+        one: "%{count} post"
+        other: "%{count} posts"
+      statuses_long:
+        one: "%{count} individual post hidden"
+        other: "%{count} individual posts hidden"
       title: Filters
     new:
       save: Save new filter
       title: Add new filter
+    statuses:
+      back_to_filter: Back to filter
+      batch:
+        remove: Remove from filter
+      index:
+        hint: This filter applies to select individual posts regardless of other criteria. You can add more posts to this filter from the web interface.
+        title: Filtered posts
   footer:
     developers: Developers
     more: More…
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index 5d3e1e367..3eabb665a 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -26,16 +26,18 @@ eo:
 
       '
     learn_more: Lerni pli
+    logged_in_as_html: Vi nun salutis kiel %{username}.
     logout_before_registering: Vi jam salutis.
-    privacy_policy: Privateca politiko
+    privacy_policy: Politiko de privateco
     rules: Reguloj de la servilo
     see_whats_happening: Vidi kio okazas
-    server_stats: Servo statuso
+    server_stats: 'Statistikoj de la servilo:'
     source_code: Fontkodo
     status_count_after:
       one: mesaĝo
       other: mesaĝoj
     status_count_before: Kie skribiĝis
+    tagline: Malcentrigita socia retejo
     terms: Kondiĉoj de la servo
     unavailable_content: Moderigitaj serviloj
     unavailable_content_description:
@@ -108,9 +110,9 @@ eo:
       delete: Forigi datumojn
       deleted: Forigita
       demote: Degradi
-      disable: Malebligi
-      disable_two_factor_authentication: Malebligi 2FA
-      disabled: Malebligita
+      disable: Frostigi
+      disable_two_factor_authentication: Malaktivigi 2FA-n
+      disabled: Frostigita
       display_name: Montrata nomo
       domain: Domajno
       edit: Redakti
@@ -220,9 +222,9 @@ eo:
         destroy_ip_block: Forigi IP-regulon
         destroy_status: Forigi mesaĝon
         destroy_unavailable_domain: Forigi Nehaveblan Domajnon
-        disable_2fa_user: Malebligi 2FA
-        disable_custom_emoji: Malebligi Propran Emoĝion
-        disable_user: Malebligi uzanton
+        disable_2fa_user: Malaktivigi 2FA-n
+        disable_custom_emoji: Malaktivigi la proprajn emoĝiojn
+        disable_user: Malaktivigi la uzanton
         enable_custom_emoji: Ebligi Propran Emoĝion
         enable_sign_in_token_auth_user: Aktivigi la aŭtentigon de peco per retpoŝto por la uzanto
         enable_user: Ebligi uzanton
@@ -265,9 +267,9 @@ eo:
         destroy_email_domain_block_html: "%{name} malblokis retpoŝtan domajnon %{target}"
         destroy_ip_block_html: "%{name} forigis regulon por IP %{target}"
         destroy_status_html: "%{name} forigis mesaĝojn de %{target}"
-        disable_2fa_user_html: "%{name} malebligis dufaktoran aŭtentigon por uzanto %{target}"
-        disable_custom_emoji_html: "%{name} malebligis emoĝion %{target}"
-        disable_user_html: "%{name} malebligis ensaluton por uzanto %{target}"
+        disable_2fa_user_html: "%{name} malaktivigis la postulon de la dufaktora aŭtentigo por la uzanto %{target}"
+        disable_custom_emoji_html: "%{name} neebligis la emoĝion %{target}"
+        disable_user_html: "%{name} neebligis la saluton de la uzanto %{target}"
         enable_custom_emoji_html: "%{name} ebligis emoĝion %{target}"
         enable_user_html: "%{name} ebligis ensaluton por uzanto %{target}"
         memorialize_account_html: "%{name} ŝanĝis la konton de %{target} al memora paĝo"
@@ -310,9 +312,9 @@ eo:
       created_msg: Emoĝio sukcese kreita!
       delete: Forigi
       destroyed_msg: Emoĝio sukcese forigita!
-      disable: Malebligi
-      disabled: Malebligita
-      disabled_msg: Emoĝio sukcese malebligita
+      disable: Neebligi
+      disabled: Neebligita
+      disabled_msg: La emoĝio sukcese neebligita
       emoji: Emoĝio
       enable: Ebligi
       enabled: Ebligita
@@ -458,11 +460,11 @@ eo:
       add_new: Aldoni novan ripetilon
       delete: Forigi
       description_html: "<strong>Fratara ripetilo</strong> estas survoja servilo, kiu interŝanĝas grandan kvanton de publikaj mesaĝoj inter serviloj, kiuj abonas kaj publikigas al ĝi. <strong>Ĝi povas helpi etajn kaj mezgrandajn servilojn malkovri enhavon de la fediverse</strong>, kio normale postulus al lokaj uzantoj mane sekvi homojn de foraj serviloj."
-      disable: Malebligi
-      disabled: Malebligita
+      disable: Neebligi
+      disabled: Neebligita
       enable: Ebligi
       enable_hint: Post ebligo, via servilo abonos ĉiujn publikajn mesaĝojn de tiu ripetilo, kaj komencos sendi publikajn mesaĝojn de la servilo al ĝi.
-      enabled: Malebligita
+      enabled: Ebligita
       inbox_url: URL de la ripetilo
       pending: Atendante aprobon de la ripetilo
       save_and_enable: Konservi kaj ebligi
@@ -618,7 +620,7 @@ eo:
     strikes:
       actions:
         delete_statuses: "%{name} forigis afiŝojn de %{target}"
-        disable: "%{name} malebligis la konton de %{target}"
+        disable: "%{name} frostigis la konton de %{target}"
         suspend: "%{name} suspendis la konton de %{target}"
       appeal_approved: Apelaciita
     system_checks:
@@ -644,6 +646,9 @@ eo:
         allow_account: Permesi aŭtoron
         disallow: Malpermesi afiŝon
         disallow_account: Malpermesi aŭtoron
+        shared_by:
+          one: Kundividita kaj aldonita al preferaĵoj unufoje
+          other: Kundividita kaj aldonita al preferaĵoj %{friendly_count}-foje
         title: Tendencantaj afiŝoj
       tags:
         dashboard:
@@ -660,7 +665,7 @@ eo:
   admin_mailer:
     new_appeal:
       actions:
-        disable: por malebligi ties konton
+        disable: por frostigi ties konton
     new_pending_account:
       body: La detaloj de la nova konto estas sube. Vi povas aprobi aŭ Malakcepti ĉi kandidatiĝo.
       subject: Nova konto atendas por recenzo en %{instance} (%{username})
@@ -765,7 +770,7 @@ eo:
       invalid_signature: 올바른 Ed25519 시그니처가 아닙니다
   date:
     formats:
-      default: "%d de %b %Y"
+      default: "%Y-%b-%d"
       with_month_name: "%e-a de %B %Y"
   datetime:
     distance_in_words:
@@ -858,7 +863,7 @@ eo:
     errors:
       invalid_context: Neniu aŭ nevalida kunteksto donita
     index:
-      contexts: Filtri en %{contexts}
+      contexts: Filtriloj en %{contexts}
       delete: Forigi
       empty: Vi havas neniun filtrilon.
       expires_in: Eksvalidiĝi en %{distance}
@@ -922,7 +927,7 @@ eo:
       one: 1 uzo
       other: "%{count} uzoj"
     max_uses_prompt: Neniu limo
-    prompt: Krei kaj diskonigi ligilojn al aliaj por doni aliron al ĉi tiu servilo
+    prompt: Generi kaj kundividi ligilojn kun aliaj personoj por doni aliron al ĉi tiu servilo
     table:
       expires_at: Eksvalidiĝas je
       uses: Uzoj
@@ -994,9 +999,9 @@ eo:
       subject: "%{name} menciis vin"
       title: Nova mencio
     reblog:
-      body: "%{name} diskonigis vian mesaĝon:"
-      subject: "%{name} diskonigis vian mesaĝon"
-      title: Nova diskonigo
+      body: 'Via mesaĝo estas suprenigita de %{name}:'
+      subject: "%{name} suprenigis vian mesaĝon"
+      title: Nova suprenigo
     status:
       subject: "%{name} ĵus afiŝita"
     update:
@@ -1076,8 +1081,8 @@ eo:
       proceed: Konfirmi la stelumon
       prompt: 'Vi volas aldoni ĉi tiun mesaĝon al viaj preferaĵoj:'
     reblog:
-      proceed: Konfirmi la diskonigon
-      prompt: 'Vi volas diskonigi ĉi tiun mesaĝon:'
+      proceed: Procedi pri la suprenigo
+      prompt: 'Vi deziras suprenigi ĉi tiun mesaĝon:'
     reply:
       proceed: Konfirmi la respondon
       prompt: 'Vi volas respondi al ĉi tiu mesaĝo:'
@@ -1161,7 +1166,7 @@ eo:
       video:
         one: "%{count} video"
         other: "%{count} videoj"
-    boosted_from_html: Diskonigita de %{acct_link}
+    boosted_from_html: Suprenigita de %{acct_link}
     content_warning: 'Averto de la enhavo: %{warning}'
     default_language: Same kiel lingvo de la fasado
     disallowed_hashtags:
@@ -1172,7 +1177,7 @@ eo:
     pin_errors:
       limit: Vi jam atingis la maksimuman nombron de alpinglitaj mesaĝoj
       ownership: Mesaĝo de iu alia ne povas esti alpinglita
-      reblog: Diskonigo ne povas esti alpinglita
+      reblog: Suprenigo ne povas esti alpinglita
     poll:
       total_people:
         one: "%{count} persono"
@@ -1199,7 +1204,7 @@ eo:
     enabled: Aŭtomate forigi malnovajn postojn
     exceptions: Esceptoj
     ignore_favs: Ignori la preferaĵojn
-    ignore_reblogs: Ignori akcelojn
+    ignore_reblogs: Ignori la suprenigojn
     keep_direct: Konservi rektajn mesaĝojn
     keep_direct_hint: Ne forigos viajn rektajn mesagôjn
     keep_media: Konservi la mesaĝojn kun aŭdovidaj aldonaĵoj
@@ -1216,7 +1221,7 @@ eo:
       '7889238': 3 monatoj
   stream_entries:
     pinned: Alpinglita
-    reblogged: diskonigita
+    reblogged: suprenigita
     sensitive_content: Tikla enhavo
   tags:
     does_not_match_previous_name: ne kongruas kun la antaŭa nomo
@@ -1233,8 +1238,8 @@ eo:
       time: "%H:%M"
   two_factor_authentication:
     add: Aldoni
-    disable: Malebligi
-    disabled_success: Dufaktora aŭtentigo sukcese malebligita
+    disable: Malaktivigi 2FA-n
+    disabled_success: Du-faktora aŭtentigo sukcese malaktivigita
     edit: Redakti
     enabled: Dufaktora aŭtentigo ebligita
     enabled_success: Dufaktora aŭtentigo sukcese ebligita
diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml
index c4d9ee969..72c2ad347 100644
--- a/config/locales/es-AR.yml
+++ b/config/locales/es-AR.yml
@@ -1181,6 +1181,8 @@ es-AR:
     edit:
       add_keyword: Agregar palabra clave
       keywords: Palabras clave
+      statuses: Mensajes individuales
+      statuses_hint_html: Este filtro se aplica a los mensajes individuales seleccionados, independientemente de si coinciden con las palabras clave de abajo. Podés revisar estos mensajes y eliminarlos del filtro <a href="%{path}">haciendo clic acá</a>.
       title: Editar filtro
     errors:
       deprecated_api_multiple_keywords: Estos parámetros no se pueden cambiar de esta aplicación porque se aplican a más de una palabra clave de filtro. Usá una aplicación más reciente o la interface web.
@@ -1194,10 +1196,23 @@ es-AR:
       keywords:
         one: "%{count} palabra clave"
         other: "%{count} palabras clave"
+      statuses:
+        one: "%{count} mensaje"
+        other: "%{count} mensajes"
+      statuses_long:
+        one: "%{count} mensaje individual oculto"
+        other: "%{count} mensajes individuales ocultos"
       title: Filtros
     new:
       save: Guardar nuevo filtro
       title: Agregar nuevo filtro
+    statuses:
+      back_to_filter: Volver al filtro
+      batch:
+        remove: Quitar del filtro
+      index:
+        hint: Este filtro se aplica a la selección de mensajes individuales independientemente de otros criterios. Podés agregar más mensajes a este filtro desde la interface web.
+        title: Mensajes filtrados
   footer:
     developers: Desarrolladores
     more: Más…
diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml
index 7ba46a89c..8faa88f56 100644
--- a/config/locales/es-MX.yml
+++ b/config/locales/es-MX.yml
@@ -103,11 +103,17 @@ es-MX:
       avatar: Foto de perfil
       by_domain: Dominio
       change_email:
+        changed_msg: "¡Email cambiado con éxito!"
         current_email: Correo electrónico actual
         label: Cambiar el correo electrónico
         new_email: Nuevo correo electrónico
         submit: Cambiar el correo electrónico
         title: Cambiar el correo electrónico de %{username}
+      change_role:
+        changed_msg: "¡Rol cambiado con éxito!"
+        label: Cambiar rol
+        no_role: Sin rol
+        title: Cambiar rol para %{username}
       confirm: Confirmar
       confirmed: Confirmado
       confirming: Confirmando
@@ -151,6 +157,7 @@ es-MX:
         active: Activo
         all: Todos
         pending: Pendiente
+        silenced: Limitado
         suspended: Suspendidos
         title: Moderación
       moderation_notes: Notas de moderación
@@ -158,6 +165,7 @@ es-MX:
       most_recent_ip: IP más reciente
       no_account_selected: Ninguna cuenta se cambió como ninguna fue seleccionada
       no_limits_imposed: Sin límites impuestos
+      no_role_assigned: Ningún rol asignado
       not_subscribed: No se está suscrito
       pending: Revisión pendiente
       perform_full_suspension: Suspender
@@ -184,6 +192,7 @@ es-MX:
       reset: Reiniciar
       reset_password: Reiniciar contraseña
       resubscribe: Re-suscribir
+      role: Rol
       search: Buscar
       search_same_email_domain: Otros usuarios con el mismo dominio de correo
       search_same_ip: Otros usuarios con la misma IP
@@ -640,6 +649,67 @@ es-MX:
       unresolved: No resuelto
       updated_at: Actualizado
       view_profile: Ver perfil
+    roles:
+      add_new: Añadir rol
+      assigned_users:
+        one: "%{count} usuario"
+        other: "%{count} usuarios"
+      categories:
+        administration: Administración
+        devops: DevOps
+        invites: Invitaciones
+        moderation: Moderación
+        special: Especial
+      delete: Eliminar
+      description_html: Con <strong>roles de usuario</strong>, puede personalizar las funciones y áreas de Mastodon a las que pueden acceder sus usuarios.
+      edit: Editar rol '%{name}'
+      everyone: Permisos por defecto
+      everyone_full_description_html: Este es el <strong>rol base</strong> que afecta a <strong>todos los usuarios</strong>, incluso aquellos sin un rol asignado. Todos los otros roles heredan permisos de él.
+      permissions_count:
+        one: "%{count} permiso"
+        other: "%{count} permisos"
+      privileges:
+        administrator: Administrador
+        administrator_description: Los usuarios con este permiso saltarán todos los permisos
+        delete_user_data: Borrar Datos de Usuario
+        delete_user_data_description: Permite a los usuarios eliminar los datos de otros usuarios sin demora
+        invite_users: Invitar usuarios
+        invite_users_description: Permite a los usuarios invitar a nuevas personas al servidor
+        manage_announcements: Administrar Anuncios
+        manage_announcements_description: Permite a los usuarios gestionar anuncios en el servidor
+        manage_appeals: Administrar Apelaciones
+        manage_appeals_description: Permite a los usuarios revisar apelaciones contra acciones de moderación
+        manage_blocks: Administrar Bloqueos
+        manage_blocks_description: Permite a los usuarios bloquear los proveedores de e-mail y las direcciones IP
+        manage_custom_emojis: Administrar Emojis Personalizados
+        manage_custom_emojis_description: Permite a los usuarios gestionar emojis personalizados en el servidor
+        manage_federation: Administrar Federación
+        manage_federation_description: Permite a los usuarios bloquear o permitir la federación con otros dominios, y controlar la entregabilidad
+        manage_invites: Administrar Invitaciones
+        manage_invites_description: Permite a los usuarios navegar y desactivar los enlaces de invitación
+        manage_reports: Administrar Informes
+        manage_reports_description: Permite a los usuarios revisar informes y realizar acciones de moderación basadas en ellos
+        manage_roles: Administrar Roles
+        manage_roles_description: Permite a los usuarios administrar y asignar roles por debajo de los suyos
+        manage_rules: Gestionar Reglas
+        manage_rules_description: Permite a los usuarios cambiar las reglas del servidor
+        manage_settings: Administrar Ajustes
+        manage_settings_description: Permite a los usuarios cambiar la configuración del sitio
+        manage_taxonomies: Administrar Taxonomías
+        manage_taxonomies_description: Permite a los usuarios revisar el contenido en tendencia y actualizar la configuración de las etiquetas
+        manage_user_access: Administrar Acceso de Usuarios
+        manage_user_access_description: Permite a los usuarios desactivar la autenticación de dos factores de otros usuarios, cambiar su dirección de correo electrónico y restablecer su contraseña
+        manage_users: Administrar Usuarios
+        manage_users_description: Permite a los usuarios ver los detalles de otros usuarios y realizar acciones de moderación contra ellos
+        manage_webhooks: Administrar Webhooks
+        manage_webhooks_description: Permite a los usuarios configurar webhooks para eventos administrativos
+        view_audit_log: Ver Registro de Auditoría
+        view_audit_log_description: Permite a los usuarios ver un historial de acciones administrativas en el servidor
+        view_dashboard: Ver Panel de Control
+        view_dashboard_description: Permite a los usuarios acceder al panel de control y varias métricas
+        view_devops: DevOps
+        view_devops_description: Permite a los usuarios acceder a los paneles de control Sidekiq y pgHero
+      title: Roles
     rules:
       add_new: Añadir norma
       delete: Eliminar
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 568ad46d9..8d2ed1a33 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -1181,6 +1181,8 @@ es:
     edit:
       add_keyword: Añadir palabra clave
       keywords: Palabras clave
+      statuses: Publicaciones individuales
+      statuses_hint_html: Este filtro se aplica a las publicaciones individuales seleccionadas, independientemente de si coinciden con las palabras clave de abajo. Puedes revisar estos mensajes y eliminarlos del filtro <a href="%{path}">pulsando aquí</a>.
       title: Editar filtro
     errors:
       deprecated_api_multiple_keywords: Estos parámetros no se pueden cambiar desde esta aplicación porque se aplican a más de una palabra clave de filtro. Utilice una aplicación más reciente o la interfaz web.
@@ -1194,10 +1196,23 @@ es:
       keywords:
         one: "%{count} palabra clave"
         other: "%{count} palabras clave"
+      statuses:
+        one: "%{count} publicación"
+        other: "%{count} publicaciones"
+      statuses_long:
+        one: "%{count} publicación individual oculta"
+        other: "%{count} publicaciones individuales ocultas"
       title: Filtros
     new:
       save: Guardar nuevo filtro
       title: Añadir nuevo filtro
+    statuses:
+      back_to_filter: Volver a filtrar
+      batch:
+        remove: Eliminar del filtro
+      index:
+        hint: Este filtro se aplica a la selección de publicaciones individuales independientemente de otros criterios. Puede añadir más mensajes a este filtro desde la interfaz Web.
+        title: Publicaciones filtradas
   footer:
     developers: Desarrolladores
     more: Mas…
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index bbc44d644..b48d8ab9f 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -38,6 +38,7 @@ fi:
       one: julkaisun
       other: julkaisua
     status_count_before: Julkaistu
+    tagline: Hajautettu sosiaalinen verkosto
     terms: Käyttöehdot
     unavailable_content: Moderoidut palvelimet
     unavailable_content_description:
@@ -102,11 +103,17 @@ fi:
       avatar: Profiilikuva
       by_domain: Verkkotunnus
       change_email:
+        changed_msg: Sähköpostin vaihto onnistui!
         current_email: Nykyinen sähköposti
         label: Vaihda sähköposti
         new_email: Uusi sähköposti
         submit: Vaihda sähköposti
         title: Vaihda sähköposti käyttäjälle %{username}
+      change_role:
+        changed_msg: Rooli vaihdettu onnistuneesti!
+        label: Vaihda roolia
+        no_role: Ei roolia
+        title: Vaihda roolia käyttäjälle %{username}
       confirm: Vahvista
       confirmed: Vahvistettu
       confirming: Vahvistetaan
@@ -150,6 +157,7 @@ fi:
         active: Aktiivinen
         all: Kaikki
         pending: Odottavat
+        silenced: Rajoitettu
         suspended: Jäähyllä
         title: Moderointi
       moderation_notes: Moderointimerkinnät
@@ -157,10 +165,14 @@ fi:
       most_recent_ip: Viimeisin IP
       no_account_selected: Yhtään tiliä ei muutettu, koska mitään ei valittu
       no_limits_imposed: Rajoituksia ei ole asetettu
+      no_role_assigned: Roolia ei ole määritetty
       not_subscribed: Ei tilaaja
       pending: Odottaa tarkistusta
       perform_full_suspension: Siirrä kokonaan jäähylle
       previous_strikes: Aiemmat varoitukset
+      previous_strikes_description_html:
+        one: Tällä tilillä on <strong>yksi</strong> varoitus.
+        other: Tällä tilillä on <strong>%{count}</strong> varoitusta.
       promote: Ylennä
       protocol: Protokolla
       public: Julkinen
@@ -180,6 +192,7 @@ fi:
       reset: Palauta
       reset_password: Palauta salasana
       resubscribe: Tilaa uudelleen
+      role: Rooli
       search: Hae
       search_same_email_domain: Muut käyttäjät, joilla on sama sähköpostiverkkotunnus
       search_same_ip: Muut käyttäjät samalla IP-osoitteella
@@ -358,6 +371,7 @@ fi:
       enable: Ota käyttöön
       enabled: Käytössä
       enabled_msg: Emojin käyttöönotto onnistui
+      image_hint: PNG tai GIF enintään %{size}
       list: Listaa
       listed: Listassa
       new:
@@ -414,6 +428,7 @@ fi:
       destroyed_msg: Verkkotunnuksen esto on peruttu
       domain: Verkkotunnus
       edit: Muokkaa verkkotunnuksen estoa
+      existing_domain_block: Olet jo asettanut tiukemmat rajoitukset %{name}.
       existing_domain_block_html: Olet jo asettanut %{name} tiukemmat rajat ja sinun täytyy <a href="%{unblock_url}">poistaa se</a> ensin.
       new:
         create: Luo esto
@@ -464,14 +479,43 @@ fi:
       title: Noudata suosituksia
       unsuppress: Palauta seuraa suositus
     instances:
+      availability:
+        failure_threshold_reached: Epäonnistumisen kynnys saavutettu %{date}.
+        failures_recorded:
+          one: Epäonnistuneita yrityksiä %{count} päivässä.
+          other: Epäonnistuneita yrityksiä %{count} päivää.
+        no_failures_recorded: Ei epäonnistumisia kirjattu.
+        title: Saatavuus
+        warning: Viimeisin yritys yhdistää yhteys tähän palvelimeen on epäonnistunut
       back_to_all: Kaikki
       back_to_limited: Rajoitettu
       back_to_warning: Varoitus
       by_domain: Verkkotunnus
       confirm_purge: Oletko varma, että haluat pysyvästi poistaa tiedot tältä verkkotunnukselta?
+      content_policies:
+        comment: Sisäinen huomautus
+        description_html: Voit määrittää sisältökäytännöt, joita sovelletaan kaikkiin tämän verkkotunnuksen ja sen aliverkkotunnuksien tileihin.
+        policies:
+          reject_media: Hylkää media
+          reject_reports: Hylkää raportit
+          silence: Rajoitus
+          suspend: Jäädytä
+        policy: Käytännöt
+        reason: Julkinen syy
+        title: Sisällön toimintatavat
+      dashboard:
+        instance_accounts_dimension: Seuratuimmat tilit
+        instance_accounts_measure: tallennetut tilit
+        instance_followers_measure: seuraajamme siellä
+        instance_follows_measure: heidän seuraajansa täällä
+        instance_languages_dimension: Suosituimmat kielet
+        instance_media_attachments_measure: tallennetut median liitteet
+        instance_reports_measure: niitä koskevat raportit
+        instance_statuses_measure: tallennetut viestit
       delivery:
         all: Kaikki
         clear: Tyhjennä toimitusvirheet
+        failing: Epäonnistuminen
         restart: Käynnistä toimitus uudelleen
         stop: Lopeta toimitus
         unavailable: Ei saatavilla
@@ -480,6 +524,9 @@ fi:
       delivery_error_hint: Jos toimitus ei ole mahdollista %{count} päivän aikana, se merkitään automaattisesti toimittamattomaksi.
       destroyed_msg: Tiedot %{domain} on nyt jonossa välitöntä poistoa varten.
       empty: Verkkotunnuksia ei löytynyt.
+      known_accounts:
+        one: "%{count} tunnettu tili"
+        other: "%{count} tunnettua tiliä"
       moderation:
         all: Kaikki
         limited: Rajoitettu
@@ -487,12 +534,14 @@ fi:
       private_comment: Yksityinen kommentti
       public_comment: Julkinen kommentti
       purge: Tyhjennä
+      purge_description_html: Jos uskot tämän verkkotunnuksen olevan offline-tilassa, voit poistaa kaikki tilitietueet ja niihin liittyvät tiedot sinun tallennustilasta. Tämä voi kestää jonkin aikaa.
       title: Tiedossa olevat instanssit
       total_blocked_by_us: Estetty meidän toimesta
       total_followed_by_them: Heidän seuraama
       total_followed_by_us: Meidän seuraama
       total_reported: Niitä koskevat raportit
       total_storage: Medialiitteet
+      totals_time_period_hint_html: Alla näkyvät yhteenlasketut tiedot sisältävät koko ajan.
     invites:
       deactivate_all: Poista kaikki käytöstä
       filter:
@@ -547,6 +596,7 @@ fi:
       action_taken_by: Toimenpiteen tekijä
       actions:
         delete_description_html: Ilmoitetut viestit poistetaan ja kirjataan varoitus, joka auttaa sinua saman tilin tulevista rikkomuksista.
+        mark_as_sensitive_description_html: Ilmoitettujen viestien media merkitään arkaluonteisiksi ja varoitus tallennetaan, jotta voit kärjistää saman tilin tulevia rikkomuksia.
         other_description_html: Katso lisää vaihtoehtoja tilin käytöksen hallitsemiseksi ja ilmoitetun tilin viestinnän mukauttamiseksi.
         resolve_description_html: Ilmoitettua tiliä vastaan ei ryhdytä toimenpiteisiin, varoitusta ei kirjata ja raportti suljetaan.
         silence_description_html: Profiili näkyy vain niille, jotka jo seuraavat sitä tai etsivät sen manuaalisesti, mikä rajoittaa merkittävästi kattavuutta. Se voidaan aina palauttaa.
@@ -596,6 +646,20 @@ fi:
       unresolved: Ratkaisemattomat
       updated_at: Päivitetty
       view_profile: Näytä profiili
+    roles:
+      add_new: Lisää rooli
+      assigned_users:
+        one: "%{count} käyttäjä"
+        other: "%{count} käyttäjää"
+      categories:
+        administration: Ylläpito
+        devops: Operaattorit
+        invites: Kutsut
+        moderation: Moderointi
+        special: Erikois
+      delete: Poista
+      description_html: Käyttäjän <strong>roolit</strong>, voit muokata toimintoja ja alueita mitä sinun Mastodon käyttäjät voivat käyttää.
+      edit: Muokkaa "%{name}" roolia
     rules:
       add_new: Lisää sääntö
       delete: Poista
@@ -773,13 +837,36 @@ fi:
         trending_rank: 'Nousussa #%{rank}'
         usable: Voidaan käyttää
         usage_comparison: Käytetty %{today} kertaa tänään, verrattuna %{yesterday} eiliseen
+        used_by_over_week:
+          one: Yhden henkilön käyttämä viime viikon aikana
+          other: Käyttänyt %{count} henkilöä viimeisen viikon aikana
       title: Trendit
+      trending: Nousussa
     warning_presets:
       add_new: Lisää uusi
       delete: Poista
       edit_preset: Muokkaa varoituksen esiasetusta
       empty: Et ole vielä määrittänyt yhtään varoitusesiasetusta.
       title: Hallinnoi varoitusesiasetuksia
+    webhooks:
+      add_new: Lisää päätepiste
+      delete: Poista
+      disable: Poista käytöstä
+      disabled: Ei käytössä
+      edit: Muokkaa päätepistettä
+      empty: Sinulla ei ole vielä määritetty webhook-päätepisteitä.
+      enable: Ota käyttöön
+      enabled: Aktiivinen
+      enabled_events:
+        one: 1 aktivoitu tapahtuma
+        other: "%{count} aktivoitua tapahtumaa"
+      events: Tapahtumat
+      new: Uusi webhook
+      rotate_secret: Vaihda salaus
+      secret: Salainen tunnus
+      status: Tila
+      title: Webhookit
+      webhook: Webhook
   admin_mailer:
     new_appeal:
       actions:
@@ -964,10 +1051,12 @@ fi:
       appealed_msg: Valituksesi on lähetetty. Jos se hyväksytään, sinulle ilmoitetaan.
       appeals:
         submit: Lähetä valitus
+      approve_appeal: Hyväksy valitus
       associated_report: Liittyvä raportti
       created_at: Päivätty
       description_html: Nämä ovat tiliäsi koskevia toimia ja varoituksia, jotka %{instance} henkilökunta on lähettänyt sinulle.
       recipient: Osoitettu
+      reject_appeal: Hylkää valitus
       status: 'Viesti #%{id}'
       status_removed: Viesti on jo poistettu järjestelmästä
       title: "%{action} alkaen %{date}"
@@ -1030,14 +1119,23 @@ fi:
       public: Julkiset aikajanat
       thread: Keskustelut
     edit:
+      add_keyword: Lisää avainsana
+      keywords: Avainsanat
       title: Muokkaa suodatinta
     errors:
       invalid_context: Ei sisältöä tai se on virheellinen
     index:
+      contexts: Suodattimet %{contexts}
       delete: Poista
       empty: Sinulla ei ole suodattimia.
+      expires_in: Vanhenee %{distance}
+      expires_on: Vanhenee %{date}
+      keywords:
+        one: "%{count} avainsana"
+        other: "%{count} avainsanaa"
       title: Suodattimet
     new:
+      save: Tallenna uusi suodatin
       title: Lisää uusi suodatin
   footer:
     developers: Kehittäjille
@@ -1156,6 +1254,8 @@ fi:
     copy_account_note_text: 'Tämä käyttäjä siirtyi paikasta %{acct}, tässä olivat aiemmat muistiinpanosi niistä:'
   notification_mailer:
     admin:
+      report:
+        subject: "%{name} lähetti raportin"
       sign_up:
         subject: "%{name} kirjautunut"
     digest:
@@ -1165,6 +1265,9 @@ fi:
       new_followers_summary:
         one: Olet myös saanut yhden uuden seuraajan! Juhuu!
         other: Olet myös saanut %{count} uutta seuraajaa! Aivan mahtavaa!
+      subject:
+        one: "1 uusi ilmoitus viime käyntisi jälkeen 🐘"
+        other: "%{count} uutta ilmoitusta viime käyntisi jälkeen 🐘"
       title: Poissaollessasi…
     favourite:
       body: "%{name} tykkäsi tilastasi:"
@@ -1278,6 +1381,11 @@ fi:
   reports:
     errors:
       invalid_rules: ei viittaa voimassa oleviin sääntöihin
+  rss:
+    content_warning: 'Sisällön varoitus:'
+    descriptions:
+      account: Julkiset viestit lähettäjältä @%{acct}
+      tag: 'Julkiset viestit merkitty #%{hashtag}'
   scheduled_statuses:
     over_daily_limit: Olet ylittänyt %{limit} ajoitetun viestin rajan tälle päivälle
     over_total_limit: Olet ylittänyt %{limit} ajoitetun viestin rajan
@@ -1365,6 +1473,7 @@ fi:
     disallowed_hashtags:
       one: 'sisälsi aihetunnisteen jota ei sallita: %{tags}'
       other: 'sisälsi aihetunnisteet joita ei sallita: %{tags}'
+    edited_at_html: Muokattu %{date}
     errors:
       in_reply_not_found: Viesti, johon yrität vastata, ei näytä olevan olemassa.
     open_in_web: Avaa selaimessa
@@ -1435,6 +1544,9 @@ fi:
     pinned: Kiinnitetty tuuttaus
     reblogged: buustasi
     sensitive_content: Arkaluontoista sisältöä
+  strikes:
+    errors:
+      too_late: On liian myöhäistä vedota tähän varoitukseen
   tags:
     does_not_match_previous_name: ei vastaa edellistä nimeä
   terms:
@@ -1477,6 +1589,13 @@ fi:
       explanation: Pyysit täydellistä varmuuskopiota Mastodon-tilistäsi. Voit nyt ladata sen!
       subject: Arkisto on valmiina ladattavaksi
       title: Arkiston tallennus
+    suspicious_sign_in:
+      change_password: vaihda salasanasi
+      details: 'Tässä on tiedot kirjautumisesta:'
+      explanation: Olemme havainneet kirjautumisen tilillesi uudesta IP-osoitteesta.
+      further_actions_html: Jos et ollut sinä, suosittelemme, että %{action} teet välittömästi ja otat kaksivaiheisen todennuksen käyttöön tilisi turvallisuuden varmistamiseksi.
+      subject: Tiliäsi on käytetty uudesta IP-osoitteesta
+      title: Uusi kirjautuminen
     warning:
       appeal: Lähetä valitus
       appeal_description: Jos uskot, että tämä on virhe, voit hakea muutosta henkilökunnalta %{instance}.
diff --git a/config/locales/gd.yml b/config/locales/gd.yml
index bdbd26199..c98235cff 100644
--- a/config/locales/gd.yml
+++ b/config/locales/gd.yml
@@ -40,6 +40,7 @@ gd:
       other: post
       two: phost
     status_count_before: A dh’fhoillsich
+    tagline: Lìonra sòisealta sgaoilte
     terms: Teirmichean na seirbheise
     unavailable_content: Frithealaichean fo mhaorsainneachd
     unavailable_content_description:
@@ -110,11 +111,17 @@ gd:
       avatar: Avatar
       by_domain: Àrainn
       change_email:
+        changed_msg: Chaidh am post-d atharrachadh!
         current_email: Am post-d làithreach
         label: Atharraich am post-d
         new_email: Post-d ùr
         submit: Atharraich am post-d
         title: Atharraich am post-d airson %{username}
+      change_role:
+        changed_msg: Chaidh an dreuchd atharrachadh!
+        label: Atharraich an dreuchd
+        no_role: Gun dreuchd
+        title: Atharraich an dreuchd aig %{username}
       confirm: Dearbh
       confirmed: Chaidh a dhearbhachadh
       confirming: "’Ga dhearbhadh"
@@ -158,6 +165,7 @@ gd:
         active: Gnìomhach
         all: Na h-uile
         pending: Ri dhèiligeadh
+        silenced: Cuingichte
         suspended: À rèim
         title: Maorsainneachd
       moderation_notes: Nòtaichean na maorsainneachd
@@ -165,6 +173,7 @@ gd:
       most_recent_ip: An IP as ùire
       no_account_selected: Cha deach cunntas sam bith atharrachadh o nach deach gin dhiubh a thaghadh
       no_limits_imposed: Cha deach crìoch sam bith a sparradh
+      no_role_assigned: Cha deach dreuchd iomruineadh
       not_subscribed: Gun fho-sgrìobhadh
       pending: A’ feitheamh air lèirmheas
       perform_full_suspension: Cuir à rèim
@@ -193,6 +202,7 @@ gd:
       reset: Ath-shuidhich
       reset_password: Ath-shuidhich am facal-faire
       resubscribe: Fo-sgrìobh a-rithist
+      role: Dreuchd
       search: Lorg
       search_same_email_domain: Cleachdaichean eile aig a bheil an aon àrainn puist-d
       search_same_ip: Cleachdaichean eile aig a bheil an t-aon IP
@@ -667,6 +677,71 @@ gd:
       unresolved: Gun fhuasgladh
       updated_at: Air ùrachadh
       view_profile: Seall a’ phròifil
+    roles:
+      add_new: Cuir dreuchd ris
+      assigned_users:
+        few: "%{count} cleachdaichean"
+        one: "%{count} chleachdaiche"
+        other: "%{count} cleachdaiche"
+        two: "%{count} chleachdaiche"
+      categories:
+        administration: Rianachd
+        devops: DevOps
+        invites: Cuiridhean
+        moderation: Maorsainneachd
+        special: Sònraichte
+      delete: Sguab às
+      description_html: Le <strong>dreuchdan chleachdaichean</strong>, ’s urrainn dhut gnàthachadh dè na gleusan is raointean de Mhastodon as urrainn dha na cleachdaichean agad inntrigeadh.
+      edit: Deasaich an dreuchd aig “%{name}“
+      everyone: Na ceadan bunaiteach
+      everyone_full_description_html: Seo an <strong>dreuchd bhunaiteach</strong> a bheir buaidh air <strong>gach cleachdaiche</strong>, fiù an fheadhainn nach deach dreuchd iomruineadh dhaibh. Gheibh a h-uile dreuch ceadan uaipe mar dhìleab.
+      permissions_count:
+        few: "%{count} ceadan"
+        one: "%{count} chead"
+        other: "%{count} cead"
+        two: "%{count} chead"
+      privileges:
+        administrator: Rianaire
+        administrator_description: Chan eil cuingeachadh sam bith air na cleachdaichean aig bheil an cead seo
+        delete_user_data: Sguab às dàta a’ chleachdaiche
+        delete_user_data_description: Leigidh seo le cleachdaichean dàta chleachdaichean eile a sguabadh às gun dàil
+        invite_users: Thoir cuireadh do chleachdaichean
+        invite_users_description: Leigidh seo le cleachdaichean cuireadh dhan fhrithealaiche a chur gu daoine eile
+        manage_announcements: Stiùireadh nam brathan-fios
+        manage_announcements_description: Leigidh seo le cleachdaichean brathan-fios a stiùireadh air an fhrithealaiche
+        manage_appeals: Stiùireadh ath-thagraidhean
+        manage_appeals_description: Leigidh seo le cleachdaichean lèirmheas a dhèanamh air ath-thagraidhean an aghaidh gnìomhan mhaor
+        manage_blocks: Stiùireadh nam bacaidhean
+        manage_blocks_description: Leigidh seo le cleachdaichean solaraichean puist-d is seòlaidhean IP a bhacadh
+        manage_custom_emojis: Stiùireadh nan Emojis gnàthaichte
+        manage_custom_emojis_description: Leigidh seo le cleachdaichean Emojis gnàthaichte a stiùireadh air an fhrithealaiche
+        manage_federation: Stiùireadh a’ cho-nasgaidh
+        manage_federation_description: Leigidh seo le cleachdaichean an co-nasgadh le àrainnean eile a bhacadh no a cheadachadh agus stiùireadh dè ghabhas lìbhrigeadh
+        manage_invites: Stiùireadh nan cuiridhean
+        manage_invites_description: Leigidh seo le cleachdaichean ceanglaichean cuiridh a rùrachadh ’s a chur à gnìomh
+        manage_reports: Stiùireadh ghearanan
+        manage_reports_description: Leigidh seo le cleachdaichean lèirmheas a dhèanamh air gearanan agus gnìomhan maoir a ghabhail ’nan aghaidh
+        manage_roles: Stiùireadh dhreuchdan
+        manage_roles_description: Leigidh seo le cleachdaichean dreuchdan a stiùireadh is iomruineadh do dh’ìochdaran
+        manage_rules: Stiùireadh nan riaghailtean
+        manage_rules_description: Leigidh seo le cleachdaichean riaghailtean an fhrithealaiche atharrachadh
+        manage_settings: Stiùireadh nan roghainnean
+        manage_settings_description: Leigidh seo le cleachdaichean roghainnean na làraich atharrachadh
+        manage_taxonomies: Stiùireadh thacsonamaidhean
+        manage_taxonomies_description: Leigidh seo le cleachdaichean lèirmheas a dhèanamh air an t-susbaint a tha a’ treandadh agus roghainnean nan tagaichean hais ùrachadh
+        manage_user_access: Stiùireadh inntrigeadh chleachdaichean
+        manage_user_access_description: Leigidh seo le cleachdaichean gun cuir iad à comas dearbhadh dà-cheumnach càich, gun atharraich iad an seòladh puist-d aca is gun ath-shuidhich iad am facal-faire aca
+        manage_users: Stiùireadh chleachdaichean
+        manage_users_description: Leigidh seo le cleachdaichean mion-fhiosrachadh càich a shealltainn agus gnìomhan maoir a ghabhail ’nan aghaidh
+        manage_webhooks: Stiùireadh nan webhooks
+        manage_webhooks_description: Leigidh seo le cleachdaichean webhooks a shuidheachadh do thachartasan na rianachd
+        view_audit_log: Coimhead air an loga sgrùdaidh
+        view_audit_log_description: Leigidh seo le cleachdaichean coimhead air eachdraidh gnìomhan na rianachd air an fhrithealaiche
+        view_dashboard: Coimhead air an deas-bhòrd
+        view_dashboard_description: Leigidh seo le cleachdaichean an deas-bhòrd agus meatrachdan inntrigeadh
+        view_devops: DevOps
+        view_devops_description: Leigidh seo le cleachdaichean na deas-bhùird aig Sidekiq is pgHero inntrigeadh
+      title: Dreuchdan
     rules:
       add_new: Cuir riaghailt ris
       delete: Sguab às
@@ -870,6 +945,28 @@ gd:
       edit_preset: Deasaich rabhadh ro-shuidhichte
       empty: Cha do mhìnich thu ro-sheataichean rabhaidhean fhathast.
       title: Stiùirich na rabhaidhean ro-shuidhichte
+    webhooks:
+      add_new: Cuir puing-dheiridh ris
+      delete: Sguab às
+      description_html: Bheir <strong>webhook</strong> comas do Mhastodon gus <strong>brathan fìor-ama</strong> a phutadh dhan aplacaid agad fhèin mu na tachartasan a thagh thu ach an adhbharaich an aplacaid agad <strong>freagairtean gu fèin-obrachail</strong>.
+      disable: Cuir à comas
+      disabled: À comas
+      edit: Deasaich a’ phuing-dheiridh
+      empty: Cha deach puing-deiridh webhook sam bith a rèiteachadh fhathast.
+      enable: Cuir an comas
+      enabled: Gnìomhach
+      enabled_events:
+        few: Tha %{count} tachartasan an comas
+        one: Tha %{count} tachartas an comas
+        other: Tha %{count} tachartas an comas
+        two: Tha %{count} thachartas an comas
+      events: Tachartasan
+      new: Webhook ùr
+      rotate_secret: Cuairtich an rùn
+      secret: Rùn soidhnich
+      status: Staid
+      title: Webhooks
+      webhook: Webhook
   admin_mailer:
     new_appeal:
       actions:
@@ -1122,14 +1219,26 @@ gd:
       public: Loidhnichean-ama poblach
       thread: Còmhraidhean
     edit:
+      add_keyword: Cuir facal-luirg ris
+      keywords: Faclan-luirg
       title: Deasaich a’ chriathrag
     errors:
+      deprecated_api_multiple_keywords: Cha ghabh na paramadairean seo atharrachadh on aplacaid seo on a bhios iad an sàs air iomadh facal-luirg na criathraige. Cleachd aplacaid nas ùire no an eadar-aghaidh-lìn.
       invalid_context: Cha deach co-theacs a sholar no tha e mì-dhligheach
     index:
+      contexts: Criathradh am broinn %{contexts}
       delete: Sguab às
       empty: Chan eil criathrag agad.
+      expires_in: Falbhaidh an ùine air an ceann %{distance}
+      expires_on: Falbhaidh an ùine air %{date}
+      keywords:
+        few: "%{count} faclan-luirg"
+        one: "%{count} fhacal-luirg"
+        other: "%{count} facal-luirg"
+        two: "%{count} fhacal-luirg"
       title: Criathragan
     new:
+      save: Sàbhail a’ chriathrag ùr
       title: Cuir criathrag ùr ris
   footer:
     developers: Luchd-leasachaidh
@@ -1252,6 +1361,8 @@ gd:
     copy_account_note_text: 'Da cleachdaiche air gluasad o %{acct}, seo na nòtaichean a bh’ agad mu dhèidhinn roimhe:'
   notification_mailer:
     admin:
+      report:
+        subject: Rinn %{name} gearan
       sign_up:
         subject: Chlàraich %{name}
     digest:
@@ -1328,7 +1439,7 @@ gd:
   polls:
     errors:
       already_voted: Chuir thu bhòt sa chunntas-bheachd seo mu thràth
-      duplicate_options: " – tha nithean dùblaichte ann"
+      duplicate_options: "– tha nithean dùblaichte ann"
       duration_too_long: "– tha seo ro fhad air falbh san àm ri teachd"
       duration_too_short: "– tha seo ro aithghearr"
       expired: Tha an cunntas-bheachd air a thighinn gu crìoch
diff --git a/config/locales/gl.yml b/config/locales/gl.yml
index a5baa17f2..5610272b7 100644
--- a/config/locales/gl.yml
+++ b/config/locales/gl.yml
@@ -1181,6 +1181,8 @@ gl:
     edit:
       add_keyword: Engadir palabra chave
       keywords: Palabras chave
+      statuses: Publicacións individuais
+      statuses_hint_html: Este filtro aplícase para seleccionar publicacións individuais independentemente de se concordan coas palabras chave aquí indicadas. Podes revisar estas publicacións e eliminalas do filtro <a href="%{path}">premendo aquí</a>.
       title: Editar filtro
     errors:
       deprecated_api_multiple_keywords: Estes parámetros non se poden cambiar desde esta aplicación porque son de aplicación a máis dun filtro de palabras chave. Usa unha aplicación máis recente ou a interface web.
@@ -1194,10 +1196,23 @@ gl:
       keywords:
         one: "%{count} palabra chave"
         other: "%{count} palabras chave"
+      statuses:
+        one: "%{count} publicación"
+        other: "%{count} publicacións"
+      statuses_long:
+        one: "%{count} publicación individual agochada"
+        other: "%{count} publicacións individuais agochadas"
       title: Filtros
     new:
       save: Gardar o novo filtro
       title: Engadir novo filtro
+    statuses:
+      back_to_filter: Volver ao filtro
+      batch:
+        remove: Eliminar do filtro
+      index:
+        hint: Este filtro aplícase para seleccionar publicacións individuais independentemente de outros criterios. Podes engadir máis publicacións a este filtro desde a interface Web.
+        title: Publicacións filtradas
   footer:
     developers: Desenvolvedoras
     more: Máis…
diff --git a/config/locales/he.yml b/config/locales/he.yml
index 74fee81cc..2106423bc 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -200,15 +200,15 @@ he:
         send: שלח מחדש דוא"ל אימות
         success: הודעת האימייל נשלחה בהצלחה!
       reset: איפוס
-      reset_password: אתחול סיסמא
+      reset_password: איפוס סיסמה
       resubscribe: להרשם מחדש
       role: תפקיד
       search: חיפוש
       search_same_email_domain: משתמשים אחרים מאותו דומיין דוא"ל
       search_same_ip: משתמשים אחרים מאותה כתובת IP
       security_measures:
-        only_password: סיסמא בלבד
-        password_and_2fa: סיסמא ואימות דו-גורמי
+        only_password: סיסמה בלבד
+        password_and_2fa: סיסמה ואימות דו-שלבי
       sensitive: מאולצים לרגישות
       sensitized: מסומנים כרגישים
       shared_inbox_url: תיבה משותפת לדואר נכנס
@@ -277,7 +277,7 @@ he:
         reject_user: דחיית משתמש
         remove_avatar_user: הסרת תמונת פרופיל
         reopen_report: פתיחת דו"ח מחדש
-        reset_password_user: איפוס סיסמא
+        reset_password_user: איפוס סיסמה
         resolve_report: פתירת דו"ח
         sensitive_account: חשבון רגיש לכח
         silence_account: הגבלת חשבון
@@ -328,7 +328,7 @@ he:
         reject_user_html: "%{name} דחו הרשמה מ-%{target}"
         remove_avatar_user_html: "%{name} הסירו את תמונת הפרופיל של %{target}"
         reopen_report_html: '%{name} פתח מחדש דו"ח %{target}'
-        reset_password_user_html: "%{name} איפס/ה סיסמא עבור המשתמש %{target}"
+        reset_password_user_html: הסיסמה עבור המשתמש %{target} התאפסה על־ידי %{name}
         resolve_report_html: '%{name} פתר/ה דו"ח %{target}'
         sensitive_account_html: "%{name} סימן/ה את המדיה של %{target} כרגיש"
         silence_account_html: "%{name} הגביל/ה את חשבונו של %{target}"
@@ -1036,7 +1036,7 @@ he:
     your_token: אסימון הגישה שלך
   auth:
     apply_for_account: בקשת הזמנה
-    change_password: סיסמא
+    change_password: סיסמה
     checkbox_agreement_html: אני מסכים/ה ל<a href="%{rules_path}" target="_blank">כללי השרת</a> ול<a href="%{terms_path}" target="_blank">תנאי השימוש</a>
     checkbox_agreement_without_rules_html: אני מסכים/ה ל<a href="%{terms_path}" target="_blank">תנאי השימוש</a>
     delete_account: מחיקת חשבון
@@ -1048,7 +1048,7 @@ he:
     didnt_get_confirmation: לא התקבלו הוראות אימות?
     dont_have_your_security_key: אין לך מפתח אבטחה?
     forgot_password: הנשתכחה סיסמתך?
-    invalid_reset_password_token: אסימון איפוס הסיסמא לא תקין או פג תוקף. נא לבקש אחד חדש.
+    invalid_reset_password_token: טוקן איפוס הסיסמה אינו תקין או שפג תוקף. נא לבקש אחד חדש.
     link_to_otp: נא להכניס את קוד האימות הדו-גורמי מהטלפון או את קוד האחזור
     link_to_webauth: נא להשתמש במכשיר מפתח האבטחה
     log_in_with: התחבר באמצעות
@@ -1063,9 +1063,9 @@ he:
     register: הרשמה
     registration_closed: "%{instance} לא מקבל חברים חדשים"
     resend_confirmation: שלח הוראות אימות בשנית
-    reset_password: איפוס סיסמא
-    security: החלפת סיסמא
-    set_new_password: שינוי סיסמא
+    reset_password: איפוס סיסמה
+    security: אבטחה
+    set_new_password: סיסמה חדשה
     setup:
       email_below_hint_html: אם כתובת הדוא"ל להלן לא נכונה, ניתן לשנותה כאן ולקבל דוא"ל אישור חדש.
       email_settings_hint_html: דוא"ל האישור נשלח ל-%{email}. אם כתובת הדוא"ל הזו לא נכונה, ניתן לשנותה בהגדרות החשבון.
@@ -1095,8 +1095,8 @@ he:
   challenge:
     confirm: המשך
     hint_html: "<strong>טיפ:</strong> לא נבקש את סיסמתך שוב בשעה הקרובה."
-    invalid_password: סיסמא שגויה
-    prompt: אשר/י סיסמא להמשך
+    invalid_password: סיסמה שגויה
+    prompt: יש לאשר את הסיסמה כדי להמשיך
   crypto:
     errors:
       invalid_key: זהו לא מפתח Ed25519 או Curve25519 קביל
@@ -1121,7 +1121,7 @@ he:
       x_seconds: "%{count} שניות"
   deletes:
     challenge_not_passed: המידע שהכנסת לא היה נכון
-    confirm_password: נא להכניס את הסיסמא הנוכחית כדי לוודא את זהותך
+    confirm_password: נא להכניס את הסיסמה הנוכחית כדי לאמת את זהותך
     confirm_username: נא להכניס את שם המשתמש כדאי לאשר את הפעולה
     proceed: מחיקת חשבון
     success_msg: חשבונך נמחק בהצלחה
@@ -1308,7 +1308,7 @@ he:
   login_activities:
     authentication_methods:
       otp: יישומון אימות דו-שלבי
-      password: סיסמא
+      password: סיסמה
       sign_in_token: קוד אימות בדוא"ל
       webauthn: מפתחות אבטחה
     description_html: אם את/ה רואה פעילות שאינך מזהה, אנא שנה/י את סיסמתך והפעל/י אימות דו-גורמי.
@@ -1672,6 +1672,87 @@ he:
   tags:
     does_not_match_previous_name: לא תואם את השם האחרון
   terms:
+    body_html: |
+      <h2>מדיניות פרטיות</h2>
+      <h3 id="collect">איזה מידע אנחנו אוספים ?</h3>
+
+      <ul>
+        <li><em>מידע חשבון בסיסי</em>: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly.</li>
+        <li><em>Posts, following and other public information</em>: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public.</li>
+        <li><em>Direct and followers-only posts</em>: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. <em>Please keep in mind that the operators of the server and any receiving server may view such messages</em>, and that recipients may screenshot, copy or otherwise re-share them. <em>Do not share any sensitive information over Mastodon.</em></li>
+        <li><em>IPs and other metadata</em>: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server.</li>
+      </ul>
+
+      <hr class="spacer" />
+
+      <h3 id="use">What do we use your information for?</h3>
+
+      <p>Any of the information we collect from you may be used in the following ways:</p>
+
+      <ul>
+        <li>To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline.</li>
+        <li>To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations.</li>
+        <li>The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions.</li>
+      </ul>
+
+      <hr class="spacer" />
+
+      <h3 id="protect">How do we protect your information?</h3>
+
+      <p>We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account.</p>
+
+      <hr class="spacer" />
+
+      <h3 id="data-retention">What is our data retention policy?</h3>
+
+      <p>We will make a good faith effort to:</p>
+
+      <ul>
+        <li>Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days.</li>
+        <li>Retain the IP addresses associated with registered users no more than 12 months.</li>
+      </ul>
+
+      <p>You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image.</p>
+
+      <p>You may irreversibly delete your account at any time.</p>
+
+      <hr class="spacer"/>
+
+      <h3 id="cookies">Do we use cookies?</h3>
+
+      <p>Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account.</p>
+
+      <p>We use cookies to understand and save your preferences for future visits.</p>
+
+      <hr class="spacer" />
+
+      <h3 id="disclose">Do we disclose any information to outside parties?</h3>
+
+      <p>We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety.</p>
+
+      <p>Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this.</p>
+
+      <p>When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password.</p>
+
+      <hr class="spacer" />
+
+      <h3 id="children">Site usage by children</h3>
+
+      <p>If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (<a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation">General Data Protection Regulation</a>) do not use this site.</p>
+
+      <p>If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children's Online Privacy Protection Act</a>) do not use this site.</p>
+
+      <p>Law requirements can be different if this server is in another jurisdiction.</p>
+
+      <hr class="spacer" />
+
+      <h3 id="changes">Changes to our Privacy Policy</h3>
+
+      <p>If we decide to change our privacy policy, we will post those changes on this page.</p>
+
+      <p>This document is CC-BY-SA. It was last updated May 26, 2022.</p>
+
+      <p>Originally adapted from the <a href="https://github.com/discourse/discourse">Discourse privacy policy</a>.</p>
     title: תנאי שימוש ומדיניות פרטיות ב-%{instance}
   themes:
     contrast: מסטודון (ניגודיות גבוהה)
diff --git a/config/locales/is.yml b/config/locales/is.yml
index 943fff632..db856011b 100644
--- a/config/locales/is.yml
+++ b/config/locales/is.yml
@@ -1181,6 +1181,8 @@ is:
     edit:
       add_keyword: Bæta við stikkorði
       keywords: Stikkorð
+      statuses: Einstakar færslur
+      statuses_hint_html: Þessi sía virkar til að velja stakar færslur burtséð frá því hvort þær samsvari stikkorðunum hér fyrir neðan. Þú getur yfirfarið þessar færslur og fjarlægt þær úr síunni með því að <a href="%{path}">smella hér</a>.
       title: Breyta síu
     errors:
       deprecated_api_multiple_keywords: Þessum viðföngum er ekki hægt að breyta úr þessu forriti, þar sem þau eiga við fleiri en eitt stikkorð síu. Notaðu nýrra forrit eða farðu í vefviðmótið.
@@ -1194,10 +1196,23 @@ is:
       keywords:
         one: "%{count} stikkorð"
         other: "%{count} stikkorð"
+      statuses:
+        one: "%{count} færsla"
+        other: "%{count} færslur"
+      statuses_long:
+        one: "%{count} stök færsla falin"
+        other: "%{count} stakar færslur faldar"
       title: Síur
     new:
       save: Vista nýja síu
       title: Bæta við nýrri síu
+    statuses:
+      back_to_filter: Til baka í síu
+      batch:
+        remove: Fjarlægja úr síu
+      index:
+        hint: Þessi sía virkar til að velja stakar færslur án tillits til annarra skilyrða. Þú getur bætt fleiri færslum í þessa síu í vefviðmótinu.
+        title: Síaðar færslur
   footer:
     developers: Forritarar
     more: Meira…
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index e4c7b6d11..5dccf1a43 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -145,6 +145,7 @@ ja:
         active: アクティブ
         all: すべて
         pending: 承認待ち
+        silenced: 制限
         suspended: 停止済み
         title: モデレーション
       moderation_notes: モデレーションメモ
@@ -152,6 +153,7 @@ ja:
       most_recent_ip: 直近のIP
       no_account_selected: 何も選択されていないため、変更されていません
       no_limits_imposed: 制限なし
+      no_role_assigned: ロールが割り当てられていません
       not_subscribed: 購読していない
       pending: 承認待ち
       perform_full_suspension: 活動を完全に停止させる
@@ -177,6 +179,7 @@ ja:
       reset: リセット
       reset_password: パスワード再設定
       resubscribe: 再講読
+      role: 役割
       search: 検索
       search_same_email_domain: 同じドメインのメールアドレスを使用しているユーザー
       search_same_ip: 同じIPのユーザーを検索
@@ -621,7 +624,42 @@ ja:
       updated_at: 更新日時
       view_profile: プロフィールを表示
     roles:
+      add_new: 役割を追加
+      assigned_users:
+        other: "%{count} 人"
+      categories:
+        administration: 管理
+        devops: 開発者
+        invites: 招待
+        moderation: モデレーション
+      delete: 削除
+      description_html: "<strong>ユーザー ロール</strong>を使用すると、ユーザーがアクセスできる Mastodon の機能や領域をカスタマイズできます。"
+      edit: "'%{name}' の役割を編集"
+      everyone: デフォルトの権限
+      everyone_full_description_html: これは、割り当てられたロールを持っていないものであっても、 <strong>すべてのユーザー</strong> に影響を与える <strong>基本ロール</strong>です。 他のすべてのロールは、そこから権限を継承します。
+      permissions_count:
+        other: "%{count} つの権限"
       privileges:
+        administrator: 管理者
+        administrator_description: この権限を持つユーザーはすべての権限をバイパスします
+        delete_user_data: ユーザーデータの削除
+        delete_user_data_description: ユーザーは、遅滞なく他のユーザーのデータを削除することができます
+        invite_users: ユーザーを招待
+        invite_users_description: ユーザーがサーバーに新しい人を招待できるようにします
+        manage_announcements: お知らせの管理
+        manage_announcements_description: ユーザーがサーバー上のアナウンスを管理できるようにします
+        manage_appeals: 抗議の管理
+        manage_appeals_description: ユーザーはモデレーションアクションに対する抗議を確認できます
+        manage_blocks: ブロックの管理
+        manage_blocks_description: ユーザーが電子メールプロバイダとIPアドレスをブロックできるようにします
+        manage_custom_emojis: カスタム絵文字を管理
+        manage_custom_emojis_description: ユーザーがサーバー上のカスタム絵文字を管理できるようにします
+        manage_federation: 連合の管理
+        manage_federation_description: ユーザーが他のドメインとの連合をブロックまたは許可したり、配信を制御したりできます。
+        manage_invites: 招待を管理
+        manage_reports: レポートの管理
+        manage_reports_description: ユーザーがレポートを確認したり、モデレーションアクションを実行したりできます。
+        manage_roles: 役職の管理
         manage_rules: ルールの管理
         manage_rules_description: ユーザーがサーバールールを変更できるようにします
         manage_settings: 設定の管理
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index f290318a6..4788365c2 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -1163,6 +1163,8 @@ ko:
     edit:
       add_keyword: 키워드 추가
       keywords: 키워드
+      statuses: 개별 게시물
+      statuses_hint_html: 이 필터는 아래 키워드들의 매치 여부와는 관계 없이 선택된 개별적인 게시물들에 적용됩니다. 다음 게시물들을 검토하고 <a href="%{path}">여기를 클릭해</a> 필터에서 제거할 수 있습니다.
       title: 필터 편집
     errors:
       deprecated_api_multiple_keywords: 이 파라미터들은 하나를 초과하는 필터 키워드에 적용되기 때문에 이 응용프로그램에서 수정될 수 없습니다. 더 최신의 응용프로그램이나 웹 인터페이스를 사용하세요.
@@ -1175,10 +1177,21 @@ ko:
       expires_on: "%{date}에 만료됨"
       keywords:
         other: "%{count}개의 키워드"
+      statuses:
+        other: "%{count}개의 게시물"
+      statuses_long:
+        other: "%{count}개의 개별적인 게시물 숨겨짐"
       title: 필터
     new:
       save: 새 필터 저장
       title: 필터 추가
+    statuses:
+      back_to_filter: 필터로 돌아가기
+      batch:
+        remove: 필터에서 제거
+      index:
+        hint: 이 필터는 다른 기준에 관계 없이 선택된 개별적인 게시물들에 적용됩니다. 웹 인터페이스에서 더 많은 게시물들을 이 필터에 추가할 수 있습니다.
+        title: 필터링된 게시물
   footer:
     developers: 개발자
     more: 더 보기…
diff --git a/config/locales/ku.yml b/config/locales/ku.yml
index ccc70d9c5..497876c6c 100644
--- a/config/locales/ku.yml
+++ b/config/locales/ku.yml
@@ -19,10 +19,10 @@ ku:
     continue_to_web: Bo malpera sepanê bidomîne
     discover_users: Bikarhêneran keşf bike
     documentation: Pelbend
-    federation_hint_html: Bi ajimêrê xwe %{instance} re tu dikarî kesên rajekar û li derveyî mastodonê bişopînî.
+    federation_hint_html: Bi ajimêrê xwe %{instance} re tu dikarî kesên ji her kîjan rajekarê mastodonê bişopînî.
     get_apps: Sepaneke mobîl bicerbîne
     hosted_on: Mastodon li ser %{domain} tê pêşkêşkirin
-    instance_actor_flash: 'Ev ajimêr aktorekî aşopî ye ji bo rajekar were temsîl kirin tê bikaranîn ne ajimêra kesî ye. Ji bo armanca federasyonê dixebite û divê ney asteng kirin heta ku te xwest hemû nimûneyan asteng bikî, di vir de ger tu blogek navper bikarbînî.
+    instance_actor_flash: 'Ev ajimêr şanogereke aşopî ye ji bo rajekar were naskirin tê bikaranîn ne ajimêra kesî ye. Ji bo armanca giştî dixebite û divê neye astengkirin heya ku te xwest hemû mînakan asteng bikî, di vir de ku tu navpereke astengiyê bi kar bînî.
 
       '
     learn_more: Bêtir fêr bibe
@@ -58,14 +58,14 @@ ku:
     what_is_mastodon: Mastodon çi ye?
   accounts:
     choices_html: 'Hilbijartina %{name}:'
-    endorsements_hint: Tu dikarî kesên ku di navrûyê wep de dişopînî bipejirînî û ew li vir were nîşan kirin.
-    featured_tags_hint: Tu dikarî hashtagên teybetî li vir tê nîşan kirin di pê de derxî.
+    endorsements_hint: Tu dikarî kesên ku di navrûya tevnê de dişopînî bipejirînî û ew ê li vir were nîşankirin.
+    featured_tags_hint: Tu dikarî hashtagên taybet ên ku wê li vir werin nîşandan bibînî.
     follow: Bişopîne
     followers:
       one: Şopîner
       other: Şopîner
     following: Dişopîne
-    instance_actor_flash: Ev ajimêr listikvaneke rastkî ye ku ji bo wek nûnerê rajekar bixwe tê bikaranîn û ne bikarhênerek kesane. Ew ji bo mebestên yekbûyî tê bikaranîn û divê neyê rawestandin.
+    instance_actor_flash: Ev ajimêr listikvaneke rastkî ye ku ji bo wek nûnerê rajekar bixwe tê bikaranîn û ne bikarhênerek kesane. Ew ji bo mebestên giştî tê bikaranîn û divê neyê rawestandin.
     joined: Di %{date} de tevlî bû
     last_active: çalakiya dawî
     link_verified_on: Xwedaniya li vê girêdanê di %{date} de hatiye kontrolkirin
@@ -73,7 +73,7 @@ ku:
     moved_html: "%{name} bar kire %{new_profile_link}:"
     network_hidden: Ev zanyarî berdest nîne
     nothing_here: Li vir tiştek tune ye!
-    people_followed_by: Kesên ku%{name} wan dişopîne
+    people_followed_by: Kesên ku %{name} wan dişopîne
     people_who_follow: Kesên%{name} dişopîne
     pin_errors:
       following: Kesê ku tu dixwazî bipejirînî jixwe tu vê dişopînî
@@ -228,7 +228,7 @@ ku:
       view_domain: Kurte ji bo navperê bide nîşan
       warn: Hişyarî
       web: Tevn
-      whitelisted: Ji bona yekbûyînê maf tê dayîn
+      whitelisted: Ji bo demnameya giştî maf hate dayin
     action_logs:
       action_types:
         approve_appeal: Îtîrazê bipejirîne
@@ -290,7 +290,7 @@ ku:
         create_account_warning_html: "%{name} ji bo %{target} hişyariyek şand"
         create_announcement_html: "%{name} agahdarkirineke nû çêkir %{target}"
         create_custom_emoji_html: "%{name} emojîyeke nû ya %{target} bar kir"
-        create_domain_allow_html: "%{name} bi navperê %{target} re maf da federeyê"
+        create_domain_allow_html: "%{name} bi navperê %{target} re maf da demnameya giştî"
         create_domain_block_html: "%{name} navpera %{target} asteng kir"
         create_email_domain_block_html: "%{name} e-nameya navperê %{target} asteng kir"
         create_ip_block_html: "%{name} ji bo IPya %{target} rêzikname saz kir"
@@ -298,7 +298,7 @@ ku:
         demote_user_html: "%{name} bikarhênerê %{target} kaşê jêr kir"
         destroy_announcement_html: "%{name} daxûyaniyeke %{target} jê bir"
         destroy_custom_emoji_html: "%{name} emojiya %{target} tune kir"
-        destroy_domain_allow_html: "%{name} bi navperê %{target} re maf neda federeyê"
+        destroy_domain_allow_html: "%{name} bi navperê %{target} re maf neda demnameya giştî"
         destroy_domain_block_html: "%{name} navpera %{target} asteng kir"
         destroy_email_domain_block_html: "%{name} astengiya li ser navpera e-nameyê %{target} rakir"
         destroy_instance_html: "%{name} navpera %{target} asteng kir"
@@ -418,10 +418,10 @@ ku:
         empty: Îtîraz nehatin dîtin.
         title: Îtîraz
     domain_allows:
-      add_new: Maf bide navpera federasyonê
-      created_msg: Ji bo federasyonê maf dayîna navperê bi serkeftî hate dayîn
-      destroyed_msg: Ji bo federasyonê maf dayîna navperê nehat dayîn
-      undo: Maf nede navpera federasyonê
+      add_new: Mafê bide navpera demnameya giştî
+      created_msg: Ji bo demnameya giştî mafdayîna navperê bi serkeftî hate dayîn
+      destroyed_msg: Ji bo demnameya giştî mafdayîna navperê nehat dayîn
+      undo: Mafê nede navpera demnameya giştî
     domain_blocks:
       add_new: Astengkirina navpera nû
       created_msg: Navpera asteng kirinê nû hat şixulandin
@@ -515,7 +515,7 @@ ku:
         instance_follows_measure: şopînerên wan li vir
         instance_languages_dimension: Zimanên pir tên bikaranîn
         instance_media_attachments_measure: pêvekên medyayê tomarkirî
-        instance_reports_measure: giliyên derbarê wan de
+        instance_reports_measure: ragehandinên di derbarê wan de
         instance_statuses_measure: şandiyên tomarkirî
       delivery:
         all: Hemû
@@ -544,7 +544,7 @@ ku:
       total_blocked_by_us: Ji aliyê me ve hatiye astengkirin
       total_followed_by_them: Ji aliyê wan ve hatiye şopandin
       total_followed_by_us: Ji aliyê me ve hatiye şopandin
-      total_reported: Giliyên derheqê wan de
+      total_reported: Ragehandinên di derbarê wan de
       total_storage: Pêvekên medyayê
       totals_time_period_hint_html: Tevahiyên ku li jêr têne xuyakirin daneyên hemû deman dihewîne.
     invites:
@@ -575,7 +575,7 @@ ku:
     relays:
       add_new: Guhêrkerê nû tevlê bike
       delete: Jê bibe
-      description_html: "<strong>Guhêrkerê giştî</strong> rajekareke navberkar e ku hejmareke mezin ji şandiyan di navbera rajekaran ku jê re dibin endam û weşanê dikin diguherîne. <strong> Ew dikare ji rajekarên piçûk û navîn re bibe alîkar ku naveroka ji fendiverse </strong>ê bibîne, ku bi rengeke din pêdivî dike ku bikarhênerên herêmî bi desta li dû kesên din ên li rajekarên ji dûr be bişopînin."
+      description_html: "<strong>Guhêrkerê giştî</strong> rajekareke navberkar e ku hejmareke mezin ji şandiyan di navbera rajekaran ku jê re dibin endam û weşanê dikin diguherîne. <strong> Ew dikare ji rajekarên piçûk û navîn re bibe alîkar ku naveroka ji fediverse </strong>ê bibîne, ku bi rengeke din pêdivî dike ku bikarhênerên herêmî bi desta li dû kesên din ên li rajekarên ji dûr be bişopînin."
       disable: Neçalak bike
       disabled: Neçalakkirî
       enable: Çalak bike
@@ -585,7 +585,7 @@ ku:
       pending: Li benda pêjirandina guhêrker e
       save_and_enable: Tomar û çalak bike
       setup: Girêdanekê guhêrker saz bike
-      signatures_not_enabled: Dema ku moda ewle ya jî moda rêzoka spî çalak be guhêrker wê birêkûpêk nexebite
+      signatures_not_enabled: Dema ku moda ewle yan jî moda demnameya giştî çalak be guhêrker wê birêkûpêk nexebite
       status: Rewş
       title: Guhêrker
     report_notes:
@@ -672,13 +672,45 @@ ku:
         other: "%{count} mafdayîn"
       privileges:
         administrator: Rêvebir
+        administrator_description: Bikarhênerên xwediyê vê mafdayînan wê her mafdayîn derbas bike
+        delete_user_data: Daneyên bikarhêner jê bibe
+        delete_user_data_description: Mafê dide bikarhêneran ku daneyên bikarhênerên din bêyî derengxisitn jê bibin
         invite_users: Bikarhêneran vexwîne
+        invite_users_description: Mafê dide bikarhêneran ku mirovên nû vexwîne bo rajekarê
+        manage_announcements: Reklaman bi rê be bibe
+        manage_announcements_description: Mafê dide bikarhêneran ku reklaman bi rê ve bibin li ser vê rajekarê
+        manage_appeals: Îtîrazan bi rê ve bibe
+        manage_appeals_description: Mafê dide bikarhêneran ku îtîrazan binirxînin li dijî çalakiyên çavdêriyê
+        manage_blocks: Astengkirinan bi rê ve bibe
+        manage_blocks_description: Mafê dide bikarhêneran ku peydakarê e-nameyê û navnîşanên IP asteng bike
         manage_custom_emojis: Emojiyên kesane bi rêve bibe
+        manage_custom_emojis_description: Mafê dide bikarhêneran ku îmojî kesane bikin li ser vê rajekarê
+        manage_federation: Demnameya giştî bi rê ve bibe
+        manage_federation_description: Mafê dide bikarhêneran ku demnameya giştî bi navparên din re asteng bikin û radestkirinê kontrol bikin
         manage_invites: Vexwendinan bi rêve bibe
+        manage_invites_description: Mafê dide bikarhêneran ku li girêdanên vexwendinê bigerin û neçalak bikin
+        manage_reports: Ragihandinan bi rê ve bibe
+        manage_reports_description: Mafê dide bikarhêneran ku ragihandinan binirxînin û li dijî wan kiryarên çavdêriyê çalakiyan pêk bînin
         manage_roles: Rolan bi rêve bibe
+        manage_roles_description: Mafê dide bikarhêneran ku rolên li jêr ên xwe birêve bibin û nîşan bikin
         manage_rules: Rolan bi rêve bibe
+        manage_rules_description: Mafê dide bikarhêneran ku rêzikên rajekarê biguherînin
         manage_settings: Sazkariyan bi rê ve bibe
+        manage_settings_description: Mafê dide bikarhêneran ku sazkariyên malperê biguherînin
+        manage_taxonomies: Beşan bi rê ve bibe
+        manage_taxonomies_description: Mafê dide bikarhêneran ku naveroka rojevê binirxînin û sazkariyên hashtagê rojane bikin
+        manage_user_access: Gihiştinê bikarhêner bi rê ve bibe
+        manage_user_access_description: Mafê dide bikarhêneran ku piştrastkirina du-gavî ya bikarhênerên din neçalak bikin, navnîşana e-nameya xwe biguherînin û borînpeyva xwe ji nû ve bikin
         manage_users: Bikarhêneran bi rêve bibe
+        manage_users_description: Mafê dide bikarhêneran ku hûrguliyên bikarhênerên din bibînin û li dijî wan kiryarên çavdêriyê çalakiyan pêk bînin
+        manage_webhooks: Webhook bi rê ve bibe
+        manage_webhooks_description: Mafê dide bikarhêneran ku ji bo bûyerên rêveberî yên webhook saz bikin
+        view_audit_log: Têketinên kontrolê nîşan bide
+        view_audit_log_description: Mafê dide bikarhêneran ku dîroka çalakiyên rêveberî yên li ser rajekarê bibînin
+        view_dashboard: Destgehê nîşan bide
+        view_dashboard_description: Mafê dide bikarhêneran ku bigihîjin destgehê û pîvanên cuda
+        view_devops: Pêşdebir
+        view_devops_description: Mafê dide bikarhêneran ku bigihîjin destgehên Sidekiq û pgHero
       title: Rol
     rules:
       add_new: Rêbazekê tevlî bike
@@ -941,7 +973,7 @@ ku:
     remove: Girêdana nûçikê rake
   appearance:
     advanced_web_interface: Navrûya tevnê yê pêşketî
-    advanced_web_interface_hint: 'Heke tu bixwazin tevahiya ferehiya dîmendera xwe bi kar bînî, navrûya pêşketî ya tevnê dihêle ku tu gelek stûnên cihêreng saz bikî da ku di heman demê de bi qasî ku tu dixwazî zanyariyan bibînî: Serrûpel, agahdarî, demnameya giştî, her hejmarek ji rêzik û hashtagan.'
+    advanced_web_interface_hint: 'Ku tu bixwazî tevahiya ferehiya dîmendera xwe bi kar bînî, navrûya pêşketî ya tevnê dihêle ku tu gelek stûnên cihêreng saz bikî da ku di heman demê de bi qasî ku tu dixwazî zanyariyan bibînî: Serrûpel, agahdarî, demnameya giştî, her hejmarek ji rêzik û hashtagan.'
     animations_and_accessibility: Anîmasyon û gihînî
     confirmation_dialogs: Gotûbêjên piştrastkirî
     discovery: Vedîtin
@@ -1149,15 +1181,24 @@ ku:
       public: Demnameya gelemperî
       thread: Axaftin
     edit:
+      add_keyword: Kilîtpeyv tevî bike
       keywords: Peyvkilît
       title: Parzûnê serrast bike
     errors:
+      deprecated_api_multiple_keywords: Van parameteran ji vê sepanê nayên guhertin ji ber ku ew li ser bêtirî yek kilîtpeyvên parzûnkirî têne sepandin. Sepaneke nûtir an navrûya bikarhêneriyê ya malperê bi kar bîne.
       invalid_context: Naverok tune ye yan jî nederbasdar tê peydakirin
     index:
+      contexts: Parzûnên di %{contexts} de
       delete: Jê bibe
       empty: Parzûnên te tune ne.
+      expires_in: Di %{distance} de diqede
+      expires_on: Di %{date} de diqede
+      keywords:
+        one: "%{count} kilîtpeyv"
+        other: "%{count} kilîtpeyv"
       title: Parzûn
     new:
+      save: Parzûna nû tomar bike
       title: Parzûnek nû li zêde bike
   footer:
     developers: Pêşdebir
@@ -1227,7 +1268,7 @@ ku:
       password: borînpeyv
       sign_in_token: koda ewlehiyê bo e-nameyê
       webauthn: kilîtên ewlehiyê
-    description_html: Heke çalakiya ku nas nakî dibînî, çêtir dibe ku borînpeyva xwe biguherînî û rastandina du-gavî çalak bikî.
+    description_html: Çalakiya ku nas nakî dibînî, çêtir dibe ku borînpeyva xwe biguherînî û rastandina du-gavî çalak bikî.
     empty: Dîroka piştrastkirinê tune ye
     failed_sign_in_html: Hewldana têketinê ser neket bi%{method} ji %{ip} (%{browser}) de
     successful_sign_in_html: Bi serkeftî têketin bi %{method} ji %{ip}(%{browser}) çêbû
@@ -1696,7 +1737,7 @@ ku:
       change_password: borînpeyva xwe biguherîne
       details: 'Li vir hûrgiliyên hewldanên têketinê hene:'
       explanation: Me têketineke nû ji ajimêra te ji navnîşaneke IP ya nû dît.
-      further_actions_html: Ku ev ne tu bû, em ji te re pêşniyar dikin ku tu di tavilê de %{action} bikî û piştrastkirina du-gavî çalak bikî da ku ajimêra te di ewlehiyê de bimîne.
+      further_actions_html: Ku ev ne tu ye, em pêşniyar dikin ku tu di tavilê de %{action} û piştrastkirina du-gavî çalak bikî da ku ajimêra te di ewlehiyê de bimîne.
       subject: Ajimêra te ji navnîşaneke IP ya nû ve hatiye gihîştin
       title: Têketineke nû
     warning:
@@ -1742,7 +1783,7 @@ ku:
       review_preferences_step: Pê bawer be ku vebijêrkên xwe saz bikî, wek mînak kîjan e-nameyên ku tu dixwaziî wergirîne, an tu dixwazî weşanên te ji kîjan astê nehêniyê de kesanekirî bin. Heke nexweşiya te ya tevgerê tune be, tu dikarî hilbijêrî ku GIF ya xweser çalak bibe.
       subject: Tu bi xêr hatî Mastodon
       tip_federated_timeline: Demnameya giştî dimenêke gelemperî a Mastodon e. Lê tenê kesên ku ciranên te endamên wê ne dihewîne, ji ber vê yekê ew hemû nîne.
-      tip_following: Tu rêvebir (ên) rajeker wek berdest dişopînî. Ji bo mirovên balkêştir bibînî, demnameya herêmî û federasyonî kontrol bike.
+      tip_following: Tu rêvebir (ên) rajeker wek berdest dişopînî. Ji bo mirovên balkêştir bibînî, demnameya herêmî û giştî kontrol bike.
       tip_local_timeline: Demnameya herêmî, dimenêke bi giştî ye li ser %{instance} e. Ev ciranên te yên herî nêzik in!
       tip_mobile_webapp: Ger geroka te ya desta pêşkêşî te bike ku tu Mastodon li ser ekrana xwe ya malê lê zêde bikî, tu dikarî agahdariyên push bistînî. Ew bi gelek awayan mîna serîlêdanek xwemalî tevdigere!
       tips: Serbend
diff --git a/config/locales/lv.yml b/config/locales/lv.yml
index cc7306c09..21da83077 100644
--- a/config/locales/lv.yml
+++ b/config/locales/lv.yml
@@ -1002,9 +1002,9 @@ lv:
     sensitive_content: Sensitīvs saturs
     toot_layout: Ziņas izskats
   application_mailer:
-    notification_preferences: Mainīt e-pasta preferences
+    notification_preferences: Mainīt e-pasta uztādījumus
     salutation: "%{name},"
-    settings: 'Mainīt e-pasta preferences: %{link}'
+    settings: 'Mainīt e-pasta uztādījumus: %{link}'
     view: 'Skatījums:'
     view_profile: Skatīt profilu
     view_status: Skatīt ziņu
@@ -1692,7 +1692,7 @@ lv:
 
       <p>Jā. Sīkfaili ir nelieli faili, ko vietne vai tās pakalpojumu sniedzējs pārsūta uz jūsu datora cieto disku, izmantojot jūsu tīmekļa pārlūkprogrammu (ja atļaujat). Šīs sīkdatnes ļauj vietnei atpazīt jūsu pārlūkprogrammu un, ja jums ir reģistrēts konts, saistīt to ar jūsu reģistrēto kontu.</p>
 
-      <p>Mēs izmantojam sīkfailus, lai saprastu un saglabātu jūsu preferences turpmākiem apmeklējumiem.</p>
+      <p>Mēs izmantojam sīkfailus, lai saprastu un saglabātu jūsu uztādījumus turpmākiem apmeklējumiem.</p>
 
       <hr class="spacer" />
 
@@ -1808,8 +1808,8 @@ lv:
       final_step: 'Sāc publicēt! Pat bez sekotājiem tavas publiskās ziņas var redzēt citi, piemēram, vietējā ziņu lentā un atsaucēs. Iespējams, tu vēlēsies iepazīstināt ar sevi, izmantojot tēmturi #introductions.'
       full_handle: Tavs pilnais rokturis
       full_handle_hint: Šis ir tas, ko tu pasaki saviem draugiem, lai viņi varētu tev ziņot vai sekot tev no cita servera.
-      review_preferences_action: Mainīt preferences
-      review_preferences_step: Noteikti iestati savas preferences, piemēram, kādus e-pasta ziņojumus vēlies saņemt vai kādu konfidencialitātes līmeni vēlies iestatīt savām ziņām pēc noklusējuma. Ja tev nav kustību slimības, vari izvēlēties iespējot GIF automātisko atskaņošanu.
+      review_preferences_action: Mainīt uztādījumus
+      review_preferences_step: Noteikti iestati savas uztādījumus, piemēram, kādus e-pasta ziņojumus vēlies saņemt vai kādu konfidencialitātes līmeni vēlies iestatīt savām ziņām pēc noklusējuma. Ja tev nav kustību slimības, vari izvēlēties iespējot GIF automātisko atskaņošanu.
       subject: Laipni lūgts Mastodon
       tip_federated_timeline: Apvienotā ziņu lenta ir skats caur ugunsdzēsības šļūteni uz Mastodon tīklu. Bet tajā ir iekļauti tikai tie cilvēki, kurus abonē tavi kaimiņi, tāpēc tas nav pilnīgs.
       tip_following: Pēc noklusējuma tu seko sava servera administratoram(-iem). Lai atrastu vairāk interesantu cilvēku, pārbaudi vietējās un federālās ziņu lentas.
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index caf3370d8..e34092f8f 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -1092,8 +1092,8 @@ nl:
         other: Je hebt trouwens sinds je weg was er ook %{count} nieuwe volgers bijgekregen! Fantastisch!
       title: Tijdens jouw afwezigheid...
     favourite:
-      body: 'Jouw bericht werd door %{name} aan diens favorieten toegevoegd:'
-      subject: "%{name} voegde jouw bericht als favoriet toe"
+      body: 'Jouw bericht werd door %{name} als favoriet gemarkeerd:'
+      subject: "%{name} markeerde jouw bericht als favoriet"
       title: Nieuwe favoriet
     follow:
       body: "%{name} volgt jou nu!"
@@ -1117,6 +1117,8 @@ nl:
       title: Nieuwe boost
     status:
       subject: "%{name} heeft zojuist een bericht geplaatst"
+    update:
+      subject: "%{name} bewerkte een bericht"
   notifications:
     email_events: E-mailmeldingen voor gebeurtenissen
     email_events_hint: 'Selecteer gebeurtenissen waarvoor je meldingen wilt ontvangen:'
@@ -1190,8 +1192,8 @@ nl:
     reason_html: "<strong> Waarom is deze extra stap nodig? </strong> <code>%{instance}</code> is wellicht niet de server waarop jij je geregistreerd hebt. We verwijzen je eerst door naar jouw eigen server."
   remote_interaction:
     favourite:
-      proceed: Doorgaan met toevoegen aan jouw favorieten
-      prompt: 'Je wilt het volgende bericht aan jouw favorieten toevoegen:'
+      proceed: Doorgaan met het markeren als favoriet
+      prompt: 'Je wilt het volgende bericht als favoriet markeren:'
     reblog:
       proceed: Doorgaan met boosten
       prompt: 'Je wilt het volgende bericht boosten:'
@@ -1281,6 +1283,7 @@ nl:
     disallowed_hashtags:
       one: 'bevatte een niet toegestane hashtag: %{tags}'
       other: 'bevatte niet toegestane hashtags: %{tags}'
+    edited_at_html: Bewerkt op %{date}
     errors:
       in_reply_not_found: Het bericht waarop je probeert te reageren lijkt niet te bestaan.
     open_in_web: In de webapp openen
diff --git a/config/locales/nn.yml b/config/locales/nn.yml
index 14f9b95ad..392b927e1 100644
--- a/config/locales/nn.yml
+++ b/config/locales/nn.yml
@@ -23,13 +23,15 @@ nn:
     hosted_on: "%{domain} er vert for Mastodon"
     instance_actor_flash: "Denne brukeren er en virtuell aktør brukt til å representere selve serveren og ingen individuell bruker. Det brukes til foreningsformål og bør ikke blokkeres med mindre du vil blokkere hele instansen, hvor domeneblokkering bør brukes i stedet. \n"
     learn_more: Lær meir
+    logout_before_registering: Du er allereie logga inn.
     privacy_policy: Personvernsreglar
-    rules: Server regler
-    rules_html: 'Nedenfor er et sammendrag av reglene du må følge om du vil ha en konto på denne serveren av Mastodon:'
+    rules: Tenarreglar
+    rules_html: 'Nedanfor er eit samandrag av reglar du må fylgje dersom du vil ha ein konto på denne Mastodontenaren:'
     see_whats_happening: Sjå kva som skjer
     server_stats: 'Tenarstatistikk:'
     source_code: Kjeldekode
     status_count_before: Som skreiv
+    tagline: Desentralisert sosialt nettverk
     terms: Brukarvilkår
     unavailable_content: Utilgjengeleg innhald
     unavailable_content_description:
@@ -99,6 +101,10 @@ nn:
         new_email: Ny e-post
         submit: Byt e-post
         title: Byt e-post for %{username}
+      change_role:
+        label: Endre rolle
+        no_role: Inga rolle
+        title: Endre rolle for %{username}
       confirm: Stadfest
       confirmed: Stadfesta
       confirming: Stadfestar
@@ -170,11 +176,12 @@ nn:
       reset: Attstill
       reset_password: Attstill passord
       resubscribe: Ting på nytt
+      role: Rolle
       search: Søk
       search_same_email_domain: Andre brukarar med same e-postdomene
       search_same_ip: Andre brukarar med same IP
       security_measures:
-        only_password: Bare passord
+        only_password: Kun passord
         password_and_2fa: Passord og 2FA
       sensitized: Merket som følsom
       shared_inbox_url: Delt Innboks URL
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 9c20a8f8a..f51c231a6 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -1221,6 +1221,8 @@ pl:
     edit:
       add_keyword: Dodaj słowo kluczowe
       keywords: Słowa kluczowe
+      statuses: Pojedyncze wpisy
+      statuses_hint_html: Ten filtr ma zastosowanie do wybierania poszczególnych postów niezależnie od tego, czy pasują one do słów kluczowych poniżej. Możesz przejrzeć te posty i usunąć je z filtra <a href="%{path}">klikając tutaj</a>.
       title: Edytuj filtr
     errors:
       deprecated_api_multiple_keywords: Te parametry nie mogą zostać zmienione z tej aplikacji, ponieważ dotyczą więcej niż jednego słowa kluczowego. Użyj nowszej wersji aplikacji lub interfejsu internetowego.
@@ -1240,6 +1242,13 @@ pl:
     new:
       save: Zapisz jako nowy filtr
       title: Dodaj nowy filtr
+    statuses:
+      back_to_filter: Powrót do filtra
+      batch:
+        remove: Usuń z filtra
+      index:
+        hint: Ten filtr ma zastosowanie do wybierania poszczególnych postów niezależnie od innych kryteriów. Możesz dodać więcej postów do tego filtra z interfejsu WWW.
+        title: Filtrowane posty
   footer:
     developers: Dla programistów
     more: Więcej…
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 7cdf1f0c7..90f2db0c4 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -692,6 +692,8 @@ ru:
         invite_users_description: Позволяет пользователям приглашать новых людей на сервер
         manage_announcements: Управление объявлениями
         manage_announcements_description: Позволяет пользователям управлять объявлениями на сервере
+        view_dashboard: Открыть панель управления
+        view_devops: DevOps
       title: Роли
     rules:
       add_new: Добавить правило
diff --git a/config/locales/simple_form.ca.yml b/config/locales/simple_form.ca.yml
index f13624403..cf450f825 100644
--- a/config/locales/simple_form.ca.yml
+++ b/config/locales/simple_form.ca.yml
@@ -85,6 +85,7 @@ ca:
         ip: Introdueix una adreça IPv4 o IPv6. Pots bloquejar rangs complets amb la sintaxi CIDR. Ves a compte no et bloquegis a tu mateix!
         severities:
           no_access: Bloqueja l’accés a tots els recursos
+          sign_up_block: Els nous registres no seran possibles
           sign_up_requires_approval: Els nous registres requeriran la teva aprovació
         severity: Tria què passarà amb les sol·licituds des d’aquesta IP
       rule:
@@ -219,6 +220,7 @@ ca:
         ip: IP
         severities:
           no_access: Bloquejar l’accés
+          sign_up_block: Bloqueja registres
           sign_up_requires_approval: Limitar els registres
         severity: Regla
       notification_emails:
diff --git a/config/locales/simple_form.da.yml b/config/locales/simple_form.da.yml
index 021ff6bdf..f74bd69a4 100644
--- a/config/locales/simple_form.da.yml
+++ b/config/locales/simple_form.da.yml
@@ -85,6 +85,7 @@ da:
         ip: Angiv en IPv4- eller IPv6-adresse. Hele intervaller kan blokeres vha. CIDR-syntaksen. Pas på med ikke selv at blive låst ude!
         severities:
           no_access: Blokér adgang til alle ressourcer
+          sign_up_block: Nye tilmeldinger vil ikke være mulige
           sign_up_requires_approval: Nye tilmeldinger kræver din godkendelse
         severity: Afgør, hvordan forespørgsler fra denne IP behandles
       rule:
@@ -219,6 +220,7 @@ da:
         ip: IP
         severities:
           no_access: Blokér adgang
+          sign_up_block: Blokér tilmeldinger
           sign_up_requires_approval: Begræns tilmeldinger
         severity: Regel
       notification_emails:
diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml
index 464ed3faf..ae1923129 100644
--- a/config/locales/simple_form.de.yml
+++ b/config/locales/simple_form.de.yml
@@ -68,6 +68,11 @@ de:
         with_dns_records: Ein Versuch die DNS-Einträge der Domain aufzulösen wurde unternommen und diese Ergebnisse werden unter anderem auch geblockt
       featured_tag:
         name: 'Du möchtest vielleicht einen von diesen benutzen:'
+      filters:
+        action: Wählen Sie, welche Aktion ausgeführt werden soll, wenn ein Beitrag dem Filter entspricht
+        actions:
+          hide: Den gefilterten Inhalt vollständig ausblenden, als hätte er nie existiert
+          warn: Den gefilterten Inhalt hinter einer Warnung ausblenden, die den Filtertitel beinhaltet
       form_challenge:
         current_password: Du betrittst einen sicheren Bereich
       imports:
@@ -80,6 +85,7 @@ de:
         ip: Gebe eine IPv4- oder IPv6-Adresse an. Du kannst ganze Bereiche mit der CIDR-Syntax blockieren. Achte darauf, dass du dich nicht aussperrst!
         severities:
           no_access: Zugriff auf alle Ressourcen blockieren
+          sign_up_block: Neue Anmeldungen werden nicht möglich sein
           sign_up_requires_approval: Neue Anmeldungen erfordern deine Zustimmung
         severity: Wähle aus, was mit Anfragen aus dieser IP passiert
       rule:
@@ -91,6 +97,13 @@ de:
         name: Du kannst zum Beispiel nur die Groß- und Kleinschreibung der Buchstaben ändern, um es lesbarer zu machen
       user:
         chosen_languages: Wenn aktiviert, werden nur Beiträge in den ausgewählten Sprachen auf den öffentlichen Zeitleisten angezeigt
+        role: Die Rolle kontrolliert welche Berechtigungen ein Benutzer hat
+      user_role:
+        color: Die Farbe, die für die Rolle im gesamten UI verwendet wird, als RGB im Hexformat
+        highlighted: Dies macht die Rolle öffentlich sichtbar
+        name: Öffentlicher Name der Rolle, wenn die Rolle als Abzeichen angezeigt werden soll
+        permissions_as_keys: Benutzer mit dieser Rolle haben Zugriff auf...
+        position: Die höhere Rolle entscheidet über die Konfliktlösung in bestimmten Situationen. Bestimmte Aktionen können nur in Rollen mit geringerer Priorität ausgeführt werden
       webhook:
         events: Zu sendende Ereignisse auswählen
         url: Wo Ereignisse hingesendet werden
@@ -181,6 +194,7 @@ de:
         setting_use_pending_items: Langsamer Modus
         severity: Schweregrad
         sign_in_token_attempt: Sicherheitscode
+        title: Titel
         type: Art des Imports
         username: Profilname
         username_or_email: Profilname oder E-Mail
@@ -189,6 +203,10 @@ de:
         with_dns_records: MX-Einträge und IPs der Domain einbeziehen
       featured_tag:
         name: Hashtag
+      filters:
+        actions:
+          hide: Komplett ausblenden
+          warn: Mit einer Warnung ausblenden
       interactions:
         must_be_follower: Benachrichtigungen von Profilen blockieren, die mir nicht folgen
         must_be_following: Benachrichtigungen von Profilen blockieren, denen ich nicht folge
@@ -202,6 +220,7 @@ de:
         ip: IP-Adresse
         severities:
           no_access: Zugriff sperren
+          sign_up_block: Anmeldungen blockieren
           sign_up_requires_approval: Anmeldungen begrenzen
         severity: Regel
       notification_emails:
@@ -222,6 +241,14 @@ de:
         name: Hashtag
         trendable: Erlaube es diesen Hashtag in den Trends erscheinen zu lassen
         usable: Beiträge erlauben, diesen Hashtag zu verwenden
+      user:
+        role: Rolle
+      user_role:
+        color: Abzeichenfarbe
+        highlighted: Rolle als Abzeichen in Benutzerprofilen anzeigen
+        name: Name
+        permissions_as_keys: Berechtigungen
+        position: Priorität
       webhook:
         events: Aktivierte Ereignisse
         url: Endpunkt-URL
diff --git a/config/locales/simple_form.el.yml b/config/locales/simple_form.el.yml
index 72c98d8d5..c3a405da1 100644
--- a/config/locales/simple_form.el.yml
+++ b/config/locales/simple_form.el.yml
@@ -76,6 +76,7 @@ el:
         ip: Εισάγετε μια διεύθυνση IPv4 ή IPv6. Μπορείτε να αποκλείσετε ολόκληρο το εύρος χρησιμοποιώντας τη σύνταξη CIDR. Προσέξτε να μην κλειδώσετε τον εαυτό σας!
         severities:
           no_access: Αποκλεισμός πρόσβασης σε όλους τους πόρους
+          sign_up_block: Νέες εγγραφές δεν θα είναι δυνατές
           sign_up_requires_approval: Νέες εγγραφές θα απαιτούν την έγκριση σας
         severity: Επιλέξτε τι θα γίνεται με αιτήσεις από αυτήν την διεύθυνση IP
       rule:
@@ -198,6 +199,7 @@ el:
         ip: Διεύθυνση IP
         severities:
           no_access: Αποκλεισμός πρόσβασης
+          sign_up_block: Αποκλεισμός εγγραφών
           sign_up_requires_approval: Περιορισμός εγγραφών
         severity: Κανόνας
       notification_emails:
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 1e0ab617e..629d0c055 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -85,6 +85,7 @@ en:
         ip: Enter an IPv4 or IPv6 address. You can block entire ranges using the CIDR syntax. Be careful not to lock yourself out!
         severities:
           no_access: Block access to all resources
+          sign_up_block: New sign-ups will not be possible
           sign_up_requires_approval: New sign-ups will require your approval
         severity: Choose what will happen with requests from this IP
       rule:
@@ -219,6 +220,7 @@ en:
         ip: IP
         severities:
           no_access: Block access
+          sign_up_block: Block sign-ups
           sign_up_requires_approval: Limit sign-ups
         severity: Rule
       notification_emails:
diff --git a/config/locales/simple_form.eo.yml b/config/locales/simple_form.eo.yml
index e3089d47d..1df8b6919 100644
--- a/config/locales/simple_form.eo.yml
+++ b/config/locales/simple_form.eo.yml
@@ -39,7 +39,7 @@ eo:
         fields: Vi povas havi ĝis 4 tabelajn elementojn en via profilo
         header: Formato PNG, GIF aŭ JPG. Ĝis %{size}. Estos malgrandigita al %{dimensions}px
         inbox_url: Kopiu la URL de la ĉefpaĝo de la ripetilo, kiun vi volas uzi
-        irreversible: La filtritaj mesaĝoj malaperos por eterne, eĉ se la filtrilo estas forigita poste
+        irreversible: La filtritaj mesaĝoj malaperos por eterne, eĉ se la filtrilo poste estas forigita
         locale: La lingvo de la fasado, de retpoŝtaĵoj, kaj de sciigoj
         locked: Vi devos aprobi ĉiun peton de sekvado mane
         password: Uzu almenaŭ 8 signojn
diff --git a/config/locales/simple_form.es-AR.yml b/config/locales/simple_form.es-AR.yml
index 9e51c4d51..7e9a6e72b 100644
--- a/config/locales/simple_form.es-AR.yml
+++ b/config/locales/simple_form.es-AR.yml
@@ -85,6 +85,7 @@ es-AR:
         ip: Ingresá una dirección IPv4 ó IPv6. Podés bloquear rangos completos usando la sintaxis CIDR. ¡Tené cuidado de no bloquearte vos mismo!
         severities:
           no_access: Bloquear acceso a todos los recursos
+          sign_up_block: Los nuevos registros se deshabilitarán
           sign_up_requires_approval: Los nuevos registros requerirán tu aprobación
         severity: Elegí lo que pasará con las solicitudes desde esta dirección IP
       rule:
@@ -219,6 +220,7 @@ es-AR:
         ip: Dirección IP
         severities:
           no_access: Bloquear acceso
+          sign_up_block: Bloquear registros
           sign_up_requires_approval: Limitar registros
         severity: Regla
       notification_emails:
diff --git a/config/locales/simple_form.es-MX.yml b/config/locales/simple_form.es-MX.yml
index 582295abb..3128209e8 100644
--- a/config/locales/simple_form.es-MX.yml
+++ b/config/locales/simple_form.es-MX.yml
@@ -102,6 +102,7 @@ es-MX:
         highlighted: Esto hace que el rol sea públicamente visible
         name: Nombre público del rol, si el rol se establece para que se muestre como una insignia
         permissions_as_keys: Los usuarios con este rol tendrán acceso a...
+        position: Un rol superior decide la resolución de conflictos en ciertas situaciones. Ciertas acciones sólo pueden llevarse a cabo en roles con menor prioridad
       webhook:
         events: Seleccionar eventos para enviar
         url: Donde los eventos serán enviados
diff --git a/config/locales/simple_form.es.yml b/config/locales/simple_form.es.yml
index cd390493c..25efe37cd 100644
--- a/config/locales/simple_form.es.yml
+++ b/config/locales/simple_form.es.yml
@@ -85,6 +85,7 @@ es:
         ip: Introduzca una dirección IPv4 o IPv6. Puede bloquear rangos completos usando la sintaxis CIDR. ¡Tenga cuidado de no quedarse fuera!
         severities:
           no_access: Bloquear acceso a todos los recursos
+          sign_up_block: Los nuevos registros se deshabilitarán
           sign_up_requires_approval: Nuevos registros requerirán su aprobación
         severity: Elegir lo que pasará con las peticiones desde esta IP
       rule:
@@ -219,6 +220,7 @@ es:
         ip: IP
         severities:
           no_access: Bloquear acceso
+          sign_up_block: Bloquear registros
           sign_up_requires_approval: Limitar registros
         severity: Regla
       notification_emails:
diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml
index 0b1239f03..422dbfae8 100644
--- a/config/locales/simple_form.fi.yml
+++ b/config/locales/simple_form.fi.yml
@@ -37,6 +37,7 @@ fi:
         current_password: Turvallisuussyistä kirjoita nykyisen tilin salasana
         current_username: Vahvista kirjoittamalla nykyisen tilin käyttäjätunnus
         digest: Lähetetään vain pitkän poissaolon jälkeen ja vain, jos olet saanut suoria viestejä poissaolosi aikana
+        discoverable: Salli tuntemattomien löytää tilisi suositusten, trendien ja muiden ominaisuuksien kautta
         email: Sinulle lähetetään vahvistussähköposti
         fields: Sinulla voi olla korkeintaan 4 asiaa profiilissasi taulukossa
         header: PNG, GIF tai JPG. Enintään %{size}. Skaalataan kokoon %{dimensions} px
@@ -48,6 +49,7 @@ fi:
         phrase: Täytetään riippumatta julkaisun kirjainkoon tai sisällön varoituksesta
         scopes: Mihin sovellusliittymiin sovellus pääsee käsiksi. Jos valitset ylätason laajuuden, sinun ei tarvitse valita yksittäisiä.
         setting_aggregate_reblogs: Älä näytä uusia tehosteita viesteille, joita on äskettäin tehostettu (koskee vain äskettäin saatuja tehosteita)
+        setting_always_send_emails: Yleensä sähköposti-ilmoituksia ei lähetetä, kun käytät aktiivisesti Mastodonia
         setting_default_sensitive: Arkaluontoinen media on oletuksena piilotettu ja se voidaan näyttää yhdellä napsautuksella
         setting_display_media_default: Piilota arkaluonteiseksi merkitty media
         setting_display_media_hide_all: Piilota aina kaikki media
@@ -66,6 +68,11 @@ fi:
         with_dns_records: Annetun verkkotunnuksen DNS-tietueet yritetään ratkaista ja tulokset myös estetään
       featured_tag:
         name: 'Voit halutessasi käyttää jotakin näistä:'
+      filters:
+        action: Valitse, mikä toiminto suoritetaan, kun viesti vastaa suodatinta
+        actions:
+          hide: Piilota suodatettu sisältö kokonaan ja käyttäydy ikään kuin sitä ei olisi olemassa
+          warn: Piilota suodatettu sisältö varoituksen taakse, jossa mainitaan suodattimen otsikko
       form_challenge:
         current_password: Olet menossa suojatulle alueelle
       imports:
@@ -89,6 +96,16 @@ fi:
         name: Voit muuttaa esimerkiksi kirjaimia paremmin luettavaksi
       user:
         chosen_languages: Kun valittu, vain valituilla kielillä julkaistut viestit näkyvät julkisilla aikajanoilla
+        role: Rooli määrää, mitkä käyttöoikeudet käyttäjällä on
+      user_role:
+        color: Väri, jota käytetään roolin koko käyttöliittymässä, RGB heksamuodossa
+        highlighted: Tämä tekee roolista julkisesti näkyvän
+        name: Roolin julkinen nimi, jos rooli on asetettu näytettäväksi mekkinä
+        permissions_as_keys: Käyttäjillä, joilla on tämä rooli, on käyttöoikeus...
+        position: Korkeampi rooli ratkaisee konfliktit tietyissä tilanteissa. Tiettyjä toimintoja voidaan suorittaa vain rooleille, joiden prioriteetti on pienempi
+      webhook:
+        events: Valitse lähetettävät tapahtumat
+        url: Mihin tapahtumat lähetetään
     labels:
       account:
         fields:
@@ -150,6 +167,7 @@ fi:
         phrase: Avainsana tai lause
         setting_advanced_layout: Ota käyttöön edistynyt web käyttöliittymä
         setting_aggregate_reblogs: Ryhmitä boostaukset aikajanalla
+        setting_always_send_emails: Lähetä aina sähköposti-ilmoituksia
         setting_auto_play_gif: Toista GIF-animaatiot automaattisesti
         setting_boost_modal: Kysy vahvistusta ennen buustausta
         setting_crop_images: Rajaa kuvat avaamattomissa tuuttauksissa 16:9 kuvasuhteeseen
@@ -175,6 +193,7 @@ fi:
         setting_use_pending_items: Hidastila
         severity: Vakavuus
         sign_in_token_attempt: Turvakoodi
+        title: Otsikko
         type: Tietojen laji
         username: Käyttäjänimi
         username_or_email: Käyttäjänimi tai sähköposti
@@ -183,6 +202,10 @@ fi:
         with_dns_records: Sisällytä toimialueen MX tietueet ja IP-osoite
       featured_tag:
         name: Aihetunniste
+      filters:
+        actions:
+          hide: Piilota kokonaan
+          warn: Piilota varoituksella
       interactions:
         must_be_follower: Estä ilmoitukset käyttäjiltä, jotka eivät seuraa sinua
         must_be_following: Estä ilmoitukset käyttäjiltä, joita et seuraa
@@ -216,6 +239,17 @@ fi:
         name: Aihetunniste
         trendable: Salli tämän aihetunnisteen näkyä trendeissä
         usable: Salli postauksien käyttää tätä aihetunnistetta
+      user:
+        role: Rooli
+      user_role:
+        color: Merkin väri
+        highlighted: Näyttä rooli merkkinä käyttäjäprofiileissa
+        name: Nimi
+        permissions_as_keys: Oikeudet
+        position: Prioriteetti
+      webhook:
+        events: Tapahtumat käytössä
+        url: Päätepisteen URL
     'no': Ei
     required:
       mark: "*"
diff --git a/config/locales/simple_form.gd.yml b/config/locales/simple_form.gd.yml
index 63199e2cd..7165cb243 100644
--- a/config/locales/simple_form.gd.yml
+++ b/config/locales/simple_form.gd.yml
@@ -68,6 +68,11 @@ gd:
         with_dns_records: Thèid oidhirp a dhèanamh air fuasgladh clàran DNS na h-àrainne a chaidh a thoirt seachad agus thèid na toraidhean a bhacadh cuideachd
       featured_tag:
         name: 'Mholamaid fear dhe na tagaichean seo:'
+      filters:
+        action: Tagh na thachras nuair a bhios post a’ maidseadh na criathraige
+        actions:
+          hide: Falaich an t-susbaint chriathraichte uile gu lèir mar nach robh i ann idir
+          warn: Falaich an t-susbaint chriathraichte air cùlaibh rabhaidh a dh’innseas tiotal na criathraige
       form_challenge:
         current_password: Tha thu a’ tighinn a-steach gu raon tèarainte
       imports:
@@ -91,6 +96,16 @@ gd:
         name: Mar eisimpleir, ’s urrainn dhut measgachadh de litrichean mòra ’s beaga a chleachdadh ach an gabh a leughadh nas fhasa
       user:
         chosen_languages: Nuair a bhios cromag ris, cha nochd ach postaichean sna cànain a thagh thu air loidhnichean-ama poblach
+        role: Stiùiridh an dreuchd dè na ceadan a bhios aig cleachdaiche
+      user_role:
+        color: An datha a bhios air an dreuchd air feadh na h-eadar-aghaidh, ’na RGB san fhòrmat sia-dheicheach
+        highlighted: Le seo, chithear an dreuchd gu poblach
+        name: Ainm poblach na dreuchd ma chaidh a suidheachadh gun nochd i na baidse
+        permissions_as_keys: Gheibh na cleachdaichean aig a bheil an dreuchd seo inntrigeadh dha…
+        position: Ma tha còmhstri ann, buannaichidh an dreuchd as àirde ann an cuid a shuidheachaidhean. Tha gnìomhan sònraichte ann nach urrainn ach dreuchdan le prìomhachas ìosail a ghabhail
+      webhook:
+        events: Tagh na tachartasan a thèid a chur
+        url: Far an dèid na tachartasan a chur
     labels:
       account:
         fields:
@@ -178,6 +193,7 @@ gd:
         setting_use_pending_items: Am modh slaodach
         severity: Donad
         sign_in_token_attempt: Còd-tèarainteachd
+        title: Tiotal
         type: Seòrsa an ion-phortaidh
         username: Ainm-cleachdaiche
         username_or_email: Ainm-cleachdaiche no post-d
@@ -186,6 +202,10 @@ gd:
         with_dns_records: Gabh a-steach clàran MX agus IPan na h-àrainne
       featured_tag:
         name: Taga hais
+      filters:
+        actions:
+          hide: Falaich uile gu lèir
+          warn: Falaich le rabhadh
       interactions:
         must_be_follower: Bac na brathan nach eil o luchd-leantainn
         must_be_following: Bac na brathan o dhaoine air nach lean thu
@@ -219,6 +239,17 @@ gd:
         name: Taga hais
         trendable: Leig leis an taga hais seo gun nochd e am measg nan treandaichean
         usable: Leig le postaichean an taga hais seo a chleachdadh
+      user:
+        role: Dreuchd
+      user_role:
+        color: Dathan na baidse
+        highlighted: Seall an dreuchd ’na baidse air pròifilean nan cleachdaichean
+        name: Ainm
+        permissions_as_keys: Ceadan
+        position: Prìomhachas
+      webhook:
+        events: Na tachartas an comas
+        url: URL na puinge-deiridh
     'no': Chan eil
     recommended: Molta
     required:
diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml
index 54e2b3e43..08add2e3e 100644
--- a/config/locales/simple_form.gl.yml
+++ b/config/locales/simple_form.gl.yml
@@ -85,6 +85,7 @@ gl:
         ip: Escribe un enderezo IPv4 ou IPv6. Podes bloquear rangos completos usando a sintaxe CIDR. Ten coidado e non te bloquees a ti mesma!
         severities:
           no_access: Bloquear acceso a tódolos recursos
+          sign_up_block: Non se poderán rexistrar novas contas
           sign_up_requires_approval: Os novos rexistros requerirán a túa aprobación
         severity: Escolle que acontecerá coas peticións desde este IP
       rule:
@@ -219,6 +220,7 @@ gl:
         ip: IP
         severities:
           no_access: Bloquear acceso
+          sign_up_block: Bloquear novos rexistros
           sign_up_requires_approval: Limitar o rexistro
         severity: Regra
       notification_emails:
diff --git a/config/locales/simple_form.hu.yml b/config/locales/simple_form.hu.yml
index 7d4cd5584..aeca9b811 100644
--- a/config/locales/simple_form.hu.yml
+++ b/config/locales/simple_form.hu.yml
@@ -85,6 +85,7 @@ hu:
         ip: Írj be egy IPv4 vagy IPv6 címet. A CIDR formátum használatával teljes tartományokat tilthatsz ki. Légy óvatos, hogy magadat véletlenül se zárd ki!
         severities:
           no_access: Elérés tiltása minden erőforráshoz
+          sign_up_block: Új feliratkozások nem lesznek lehetségesek
           sign_up_requires_approval: Új regisztrációk csak a jóváhagyásoddal történhetnek majd meg
         severity: Válaszd ki, mi történjen a kérésekkel erről az IP-ről
       rule:
@@ -219,6 +220,7 @@ hu:
         ip: IP
         severities:
           no_access: Elérés letiltása
+          sign_up_block: Feliratkozások letiltása
           sign_up_requires_approval: Regisztrációk korlátozása
         severity: Szabály
       notification_emails:
diff --git a/config/locales/simple_form.is.yml b/config/locales/simple_form.is.yml
index fb0233572..8c4b648d9 100644
--- a/config/locales/simple_form.is.yml
+++ b/config/locales/simple_form.is.yml
@@ -85,6 +85,7 @@ is:
         ip: Settu inn IPv4 eða IPv6 vistfang. Þú getur lokað á svið vistfanga með því að nota CIDR-framsetningu. Gættu þess að loka ekki sjálfa/n þig úti!
         severities:
           no_access: Loka á aðgang að öllum tilföngum
+          sign_up_block: Nýskráningar verða ekki mögulegar
           sign_up_requires_approval: Nýskráningar munu þurfa samþykki þitt
         severity: Veldu hvað munir gerast við beiðnir frá þessu IP-vistfangi
       rule:
@@ -219,6 +220,7 @@ is:
         ip: IP-vistfang
         severities:
           no_access: Loka á aðgang
+          sign_up_block: Loka á nýskráningar
           sign_up_requires_approval: Takmarka nýskráningar
         severity: Regla
       notification_emails:
diff --git a/config/locales/simple_form.it.yml b/config/locales/simple_form.it.yml
index df8a25396..52620def4 100644
--- a/config/locales/simple_form.it.yml
+++ b/config/locales/simple_form.it.yml
@@ -85,6 +85,7 @@ it:
         ip: Inserisci un indirizzo IPv4 o IPv6. Puoi bloccare interi intervalli usando la sintassi CIDR. Fai attenzione a non bloccare te stesso!
         severities:
           no_access: Blocca l'accesso a tutte le risorse
+          sign_up_block: Le nuove iscrizioni non saranno possibili
           sign_up_requires_approval: Le nuove iscrizioni richiederanno la tua approvazione
         severity: Scegli cosa accadrà con le richieste da questo IP
       rule:
@@ -219,6 +220,7 @@ it:
         ip: IP
         severities:
           no_access: Blocca accesso
+          sign_up_block: Blocca iscrizioni
           sign_up_requires_approval: Limita iscrizioni
         severity: Regola
       notification_emails:
diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml
index 0140e7812..6e3996d50 100644
--- a/config/locales/simple_form.ko.yml
+++ b/config/locales/simple_form.ko.yml
@@ -85,6 +85,7 @@ ko:
         ip: IPv4 또는 IPv6 주소를 입력하세요. CIDR 문법을 사용해서 모든 범위를 차단할 수도 있습니다. 자기 자신을 잠가버리지 않도록 주의하세요!
         severities:
           no_access: 모든 자원에 대한 접근 차단
+          sign_up_block: 새 가입이 불가능하게 됩니다
           sign_up_requires_approval: 새 가입이 승인을 필요로 하도록 합니다
         severity: 해당 IP로부터의 요청에 대해 무엇이 일어나게 할 지 고르세요
       rule:
@@ -219,6 +220,7 @@ ko:
         ip: IP
         severities:
           no_access: 접근 차단
+          sign_up_block: 가입 차단
           sign_up_requires_approval: 가입 제한
         severity: 규칙
       notification_emails:
diff --git a/config/locales/simple_form.ku.yml b/config/locales/simple_form.ku.yml
index ea6db0972..d08b4bf05 100644
--- a/config/locales/simple_form.ku.yml
+++ b/config/locales/simple_form.ku.yml
@@ -70,6 +70,11 @@ ku:
         with_dns_records: Hewl tê dayîn ku tomarên DNSê yên li qada jê re hatine dayîn were çareserkirin û encamên wê jî were astengkirin
       featured_tag:
         name: 'Belkî tu yekê bi kar bînî çi van:'
+      filters:
+        action: Hilbijêre ku dema şandiyek bi parzûnê re lihevhatî be bila kîjan çalakî were pêkanîn
+        actions:
+          hide: Naveroka parzûnkirî bi tevahî veşêre, mîna ku ew tune be tevbigere
+          warn: Naveroka parzûnkirî li pişt hişyariyek ku sernavê parzûnê qal dike veşêre
       form_challenge:
         current_password: Tu dikevî qadeke ewledar
       imports:
@@ -82,6 +87,7 @@ ku:
         ip: Têkeve navnîşana IPv4 an jî IPv6'yek. Tu dikarî bi hevoksazî ya CIDR re hemî valahîyan asteng bikî. Hay ji xwe hebe ku xwe derve nehêle!
         severities:
           no_access: Gihîştina hemî çavkaniyan asteng bike
+          sign_up_block: Tomarkirinên nû wê ne pêkan bin
           sign_up_requires_approval: Tomarkirinên nû de pejirandina te pêwîste
         severity: Daxwazên ku ji vê IPyê tên dê çi bibe hilbijêre
       rule:
@@ -93,7 +99,12 @@ ku:
         name: Tîpan, mînak ji bo ku bêhtir paknivîs bibe, tenê rewşa tîpên girdek/hûrdek dikarî biguherînî
       user:
         chosen_languages: Dema were nîşankirin, tenê parvekirinên bi zimanên hilbijartî dê di rêzikên giştî de werin nîşandan
+        role: Rola kîjan mafdayînên bikarhêner heye kontrol dike
       user_role:
+        color: Renga ku were bikaranîn ji bo rola li seranserê navrûya bikarhêneriyê, wekî RGB di forma hex
+        highlighted: Ev rola xwe ji raya giştî re xuya dike
+        name: Navê giştî yê rolê, ku rol wekî nîşanekê were nîşankirin
+        permissions_as_keys: Bikarhênerên bi vê rolê wê bigihîjin...
         position: Rola bilind di hinek rewşan de biryara çareserkirina nakokiyan dide. Hinej çalakî tenê dikarin li ser rolên bi pêşanînek kêmtir bêne kirin
       webhook:
         events: Bûyeran hilbijêre bo şandinê
@@ -185,6 +196,7 @@ ku:
         setting_use_pending_items: Awayê hêdî
         severity: Asta girîngiyê
         sign_in_token_attempt: Koda ewlehiyê
+        title: Sernav
         type: Cureya têxistinê
         username: Navê bikarhêneriyê
         username_or_email: Navê bikarhêner an jî e-name
@@ -193,6 +205,10 @@ ku:
         with_dns_records: Tomarên MX û IP yên hundirê navper lê zêde bike
       featured_tag:
         name: Hashtag
+      filters:
+        actions:
+          hide: Bi tevahî veşêre
+          warn: Bi hişyariyekê veşêre
       interactions:
         must_be_follower: Danezanên ji kesên ku ne şopînerên min tên asteng bike
         must_be_following: Agahdariyan asteng bike ji kesên ku tu wan naşopînî
@@ -206,6 +222,7 @@ ku:
         ip: IP
         severities:
           no_access: Gihîştinê asteng bike
+          sign_up_block: Tomarkirinan asteng bike
           sign_up_requires_approval: Tomaran sînordar bike
         severity: Rêbaz
       notification_emails:
@@ -229,6 +246,8 @@ ku:
       user:
         role: Rol
       user_role:
+        color: Rengê nîşanê
+        highlighted: Li ser profîlên bikarhêner rola wekî nîşan bide nîşankirin
         name: Nav
         permissions_as_keys: Maf
         position: Pêşikî
diff --git a/config/locales/simple_form.lv.yml b/config/locales/simple_form.lv.yml
index ad8f3bd4d..d73da1c2a 100644
--- a/config/locales/simple_form.lv.yml
+++ b/config/locales/simple_form.lv.yml
@@ -85,6 +85,7 @@ lv:
         ip: Ievadi IPv4 vai IPv6 adresi. Izmantojot CIDR sintaksi, tu vari bloķēt visus diapazonus. Esi piesardzīgs un neizslēdz pats sevi!
         severities:
           no_access: Bloķēt piekļuvi visiem resursiem
+          sign_up_block: Jaunas pieteikšanās nebūs iespējamas
           sign_up_requires_approval: Jaunām reģistrācijām būs nepieciešams tavs apstiprinājums
         severity: Izvēlies, kas notiks ar pieprasījumiem no šīs IP adreses
       rule:
@@ -219,6 +220,7 @@ lv:
         ip: IP
         severities:
           no_access: Bloķēt piekļuvi
+          sign_up_block: Bloķēt pieteikšanās
           sign_up_requires_approval: Ierobežot reģistrēšanos
         severity: Noteikumi
       notification_emails:
diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml
index 3dd55c8b3..7bab0042d 100644
--- a/config/locales/simple_form.nl.yml
+++ b/config/locales/simple_form.nl.yml
@@ -211,7 +211,7 @@ nl:
       notification_emails:
         appeal: Iemand heeft bezwaar ingediend tegen een beslissing van een moderator
         digest: Periodiek e-mails met een samenvatting versturen
-        favourite: Wanneer iemand jouw bericht aan diens favorieten heeft toegevoegd
+        favourite: Wanneer iemand jouw bericht als favoriet markeert
         follow: Wanneer iemand jou is gaan volgen
         follow_request: Wanneer iemand jou wil volgen
         mention: Wanneer iemand jou heeft vermeld
diff --git a/config/locales/simple_form.nn.yml b/config/locales/simple_form.nn.yml
index 25bc156e1..b3b282858 100644
--- a/config/locales/simple_form.nn.yml
+++ b/config/locales/simple_form.nn.yml
@@ -85,6 +85,10 @@ nn:
         name: Du kan berre endra bruken av store/små bokstavar, t. d. for å gjera det meir leseleg
       user:
         chosen_languages: Når merka vil berre tuta på dei valde språka synast på offentlege tidsliner
+        role: Rolla kontrollerer kva tilgangar brukaren har
+      user_role:
+        highlighted: Dette gjer rolla synleg offentleg
+        permissions_as_keys: Brukarar med denne rolla vil ha tilgang til...
     labels:
       account:
         fields:
@@ -144,6 +148,7 @@ nn:
         phrase: Nykelord eller frase
         setting_advanced_layout: Skruv på det avanserte nettgrensesnittet
         setting_aggregate_reblogs: Gruppeframhevingar på tidsliner
+        setting_always_send_emails: Alltid send epostvarsel
         setting_auto_play_gif: Spel av animerte GIF-ar automatisk
         setting_boost_modal: Vis stadfesting før framheving
         setting_crop_images: Skjer bilete i ikkje-utvida tut til 16x9
@@ -169,6 +174,7 @@ nn:
         setting_use_pending_items: Saktemodus
         severity: Alvorsgrad
         sign_in_token_attempt: Trygdenykel
+        title: Tittel
         type: Importtype
         username: Brukarnamn
         username_or_email: Brukarnamn eller E-post
@@ -177,6 +183,10 @@ nn:
         with_dns_records: Ha med MX-recordar og IP-ar til domenet
       featured_tag:
         name: Emneknagg
+      filters:
+        actions:
+          hide: Gøym totalt
+          warn: Gøym med ei advarsel
       interactions:
         must_be_follower: Gøym varslingar frå folk som ikkje fylgjer deg
         must_be_following: Gøym varslingar frå folk du ikkje fylgjer
@@ -200,6 +210,7 @@ nn:
         mention: Send e-post når nokon nemner deg
         pending_account: Send e-post når ein ny konto treng gjennomgang
         reblog: Send e-post når nokon framhevar statusen din
+        report: Ny rapport er sendt
       rule:
         text: Regler
       tag:
@@ -207,6 +218,13 @@ nn:
         name: Emneknagg
         trendable: Tillat denne emneknaggen til å synast under trendar
         usable: Gje tut lov til å nytta denne emneknaggen
+      user:
+        role: Rolle
+      user_role:
+        name: Namn
+        position: Prioritet
+      webhook:
+        url: Endepunkts-URL
     'no': Nei
     required:
       mark: "*"
diff --git a/config/locales/simple_form.pt-PT.yml b/config/locales/simple_form.pt-PT.yml
index f4ff925f1..bebb00456 100644
--- a/config/locales/simple_form.pt-PT.yml
+++ b/config/locales/simple_form.pt-PT.yml
@@ -85,6 +85,7 @@ pt-PT:
         ip: Introduza um endereço IPv4 ou IPv6. Pode bloquear intervalos inteiros usando a sintaxe CIDR. Tenha cuidado para não se bloquear a sí mesmo!
         severities:
           no_access: Bloquear o acesso a todos os recursos
+          sign_up_block: Não serão possíveis novas inscrições
           sign_up_requires_approval: Novas inscrições requererão a sua aprovação
         severity: Escolha o que acontecerá com as solicitações deste IP
       rule:
@@ -219,6 +220,7 @@ pt-PT:
         ip: IP
         severities:
           no_access: Bloquear acesso
+          sign_up_block: Bloquear inscrições
           sign_up_requires_approval: Limitar inscrições
         severity: Regra
       notification_emails:
diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml
index 8f0c65dd6..60302cd08 100644
--- a/config/locales/simple_form.ru.yml
+++ b/config/locales/simple_form.ru.yml
@@ -3,7 +3,7 @@ ru:
   simple_form:
     hints:
       account_alias:
-        acct: Укажите имя_пользователя@домен учётной записи, с которой вы собираетесь мигрировать
+        acct: Укажите ник@домен учётной записи, с которой вы собираетесь мигрировать
       account_migration:
         acct: Укажите имя_пользователя@домен учётной записи, на которую вы собираетесь мигрировать
       account_warning_preset:
@@ -44,7 +44,7 @@ ru:
         inbox_url: Копировать URL с главной страницы ретранслятора, который вы хотите использовать
         irreversible: Отфильтрованные посты будут утеряны навсегда, даже если в будущем фильтр будет убран
         locale: Язык интерфейса, e-mail писем и push-уведомлений
-        locked: Подписчиков нужно будет подтверждать вручную.
+        locked: Вручную контролируйте, кто может подписываться на вас, утверждая запросы на подписку
         password: Укажите не менее 8 символов.
         phrase: Будет сопоставлено независимо от присутствия в тексте или предупреждения о содержании поста
         scopes: Какие API приложению будет позволено использовать. Если вы выберете самый верхний, нижестоящие будут выбраны автоматически.
@@ -85,6 +85,7 @@ ru:
         ip: Введите IPv4 или IPv6 адрес. Вы можете блокировать целые диапазоны, используя синтаксис CIDR. Будьте осторожны, не заблокируйте самого себя!
         severities:
           no_access: Заблокировать доступ ко всем ресурсам
+          sign_up_block: Новые регистрации будут невозможны
           sign_up_requires_approval: Новые регистрации потребуют вашего одобрения
         severity: Выберите, что будет происходить с запросами с этого IP
       rule:
@@ -99,6 +100,8 @@ ru:
         role: Роль определяет, какие разрешения есть у пользователя
       user_role:
         color: Цвет, который будет использоваться для роли в интерфейсе (UI), как RGB в формате HEX
+        highlighted: Это действие сделает роль публичной
+        name: Публичное имя роли, если роль настроена на отображение в виде значка
         permissions_as_keys: Пользователи с этой ролью будут иметь доступ...
         position: Повышение роли разрешают конфликты интересов в некоторых ситуациях. Некоторые действия могут выполняться только на ролях с более низким приоритетом
       webhook:
@@ -217,6 +220,7 @@ ru:
         ip: IP
         severities:
           no_access: Блокировать доступ
+          sign_up_block: Заблокировать регистрацию
           sign_up_requires_approval: Ограничить регистрации
         severity: Правило
       notification_emails:
@@ -240,6 +244,8 @@ ru:
       user:
         role: Роль
       user_role:
+        color: Цвет значка
+        highlighted: Отображать роль в качестве значка в профилях пользователей
         name: Название
         permissions_as_keys: Разрешения
         position: Приоритет
diff --git a/config/locales/simple_form.sl.yml b/config/locales/simple_form.sl.yml
index 02445e8fb..80f0a07ce 100644
--- a/config/locales/simple_form.sl.yml
+++ b/config/locales/simple_form.sl.yml
@@ -85,6 +85,7 @@ sl:
         ip: Vnesite naslov IPv4 oz. IPv6. S skladnjo CIDR lahko blokirate celotne obsege. Pazite, da se ne zaklenete ven!
         severities:
           no_access: Blokiraj dostop do vseh virov
+          sign_up_block: Nove registracije ne bodo možne
           sign_up_requires_approval: Za nove registracije bo potrebna vaša odobritev
         severity: Izberite, kaj se bo zgodilo z zahtevami iz tega IP-naslova
       rule:
@@ -219,6 +220,7 @@ sl:
         ip: IP
         severities:
           no_access: Blokiraj dostop
+          sign_up_block: Blokiraj registracije
           sign_up_requires_approval: Omeji število prijav
         severity: Pravilo
       notification_emails:
diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml
index 782a9cda2..4bb7d7cb7 100644
--- a/config/locales/simple_form.sv.yml
+++ b/config/locales/simple_form.sv.yml
@@ -60,6 +60,7 @@ sv:
         ip: Ange en IPv4 eller IPv6-adress. Du kan blockera hela intervall med hjälp av CIDR-syntax. Var försiktig så att du inte låser ut dig själv!
         severities:
           no_access: Blockera åtkomst till alla resurser
+          sign_up_block: Nya registreringar inte möjligt
           sign_up_requires_approval: Nya registreringar kräver ditt godkännande
         severity: Välj vad som ska hända med förfrågningar från denna IP
       rule:
@@ -176,6 +177,7 @@ sv:
         ip: IP
         severities:
           no_access: Blockera åtkomst
+          sign_up_block: Blockera registreringar
           sign_up_requires_approval: Begränsa registreringar
         severity: Regel
       notification_emails:
diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml
index 700169896..478b9d765 100644
--- a/config/locales/simple_form.th.yml
+++ b/config/locales/simple_form.th.yml
@@ -64,15 +64,15 @@ th:
       domain_allow:
         domain: โดเมนนี้จะสามารถดึงข้อมูลจากเซิร์ฟเวอร์นี้และจะประมวลผลและจัดเก็บข้อมูลขาเข้าจากโดเมน
       email_domain_block:
-        domain: อาจเป็นชื่อโดเมนที่แสดงในที่อยู่อีเมลหรือทะเบียน MX ที่ใช้อยู่ พวกเขาอาจจะได้รับการตรวจสอบเมื่อมีการสมัคร
+        domain: สิ่งนี้สามารถเป็นชื่อโดเมนที่ปรากฏในที่อยู่อีเมลหรือระเบียน MX ที่โดเมนใช้ จะตรวจสอบโดเมนเมื่อลงทะเบียน
         with_dns_records: จะทำการพยายามแปลงที่อยู่ระเบียน DNS ของโดเมนที่กำหนดและจะปิดกั้นผลลัพธ์เช่นกัน
       featured_tag:
         name: 'คุณอาจต้องการใช้หนึ่งในนี้:'
       filters:
-        action: เลือกการดำเนินการเมื่อโพสต์ตรงกับตัวกรอง
+        action: เลือกว่าการกระทำใดที่จะทำเมื่อโพสต์ตรงกับตัวกรอง
         actions:
-          hide: ซ่อนเนื้อหาที่ถูกกรองโดยสิ้นเชิง ทำตัวราวกับว่าไม่มีอยู่จริง
-          warn: ซ่อนเนื้อหาที่ถูกกรองไว้ด้านหลังคำเตือนที่กล่าวถึงชื่อตัวกรอง
+          hide: ซ่อนเนื้อหาที่กรองอยู่อย่างสมบูรณ์ ทำเสมือนว่าไม่มีเนื้อหาอยู่
+          warn: ซ่อนเนื้อหาที่กรองอยู่หลังคำเตือนที่กล่าวถึงชื่อเรื่องของตัวกรอง
       form_challenge:
         current_password: คุณกำลังเข้าสู่พื้นที่ปลอดภัย
       imports:
@@ -85,6 +85,7 @@ th:
         ip: ป้อนที่อยู่ IPv4 หรือ IPv6 คุณสามารถปิดกั้นทั้งช่วงได้โดยใช้ไวยากรณ์ CIDR ระวังอย่าล็อคตัวคุณเองออก!
         severities:
           no_access: ปิดกั้นการเข้าถึงทรัพยากรทั้งหมด
+          sign_up_block: จะไม่สามารถทำการลงทะเบียนใหม่
           sign_up_requires_approval: การลงทะเบียนใหม่จะต้องมีการอนุมัติของคุณ
         severity: เลือกสิ่งที่จะเกิดขึ้นกับคำขอจาก IP นี้
       rule:
@@ -105,7 +106,7 @@ th:
         position: บทบาทที่สูงขึ้นตัดสินใจการแก้ปัญหาข้อขัดแย้งในบางสถานการณ์ การกระทำบางอย่างสามารถทำได้เฉพาะกับบทบาทที่มีระดับความสำคัญต่ำกว่าเท่านั้น
       webhook:
         events: เลือกเหตุการณ์ที่จะส่ง
-        url: จะส่งเหตุการณ์ไปยัง
+        url: ที่ซึ่งจะส่งเหตุการณ์ไปยัง
     labels:
       account:
         fields:
@@ -205,7 +206,7 @@ th:
       filters:
         actions:
           hide: ซ่อนอย่างสมบูรณ์
-          warn: ซ่อนพร้อมคำเตือน
+          warn: ซ่อนด้วยคำเตือน
       interactions:
         must_be_follower: ปิดกั้นการแจ้งเตือนจากผู้ที่ไม่ใช่ผู้ติดตาม
         must_be_following: ปิดกั้นการแจ้งเตือนจากผู้คนที่คุณไม่ได้ติดตาม
@@ -219,6 +220,7 @@ th:
         ip: IP
         severities:
           no_access: ปิดกั้นการเข้าถึง
+          sign_up_block: ปิดกั้นการลงทะเบียน
           sign_up_requires_approval: จำกัดการลงทะเบียน
         severity: กฎ
       notification_emails:
diff --git a/config/locales/simple_form.tr.yml b/config/locales/simple_form.tr.yml
index 7281d14dd..13fde2abe 100644
--- a/config/locales/simple_form.tr.yml
+++ b/config/locales/simple_form.tr.yml
@@ -85,6 +85,7 @@ tr:
         ip: Bir IPv4 veya IPv6 adresi girin. CIDR sözdizimini kullanarak tüm aralıkları engelleyebilirsiniz. Kendinizi dışarıda bırakmamaya dikkat edin!
         severities:
           no_access: Tüm kaynaklara erişimi engelle
+          sign_up_block: Yeni kayıtlar mümkün olmayacaktır
           sign_up_requires_approval: Yeni kayıt onayınızı gerektirir
         severity: Bu IP'den gelen isteklere ne olacağını seçin
       rule:
@@ -219,6 +220,7 @@ tr:
         ip: IP
         severities:
           no_access: Erişimi engelle
+          sign_up_block: Kayıt olmayı engelle
           sign_up_requires_approval: Kayıtları sınırla
         severity: Kural
       notification_emails:
diff --git a/config/locales/simple_form.uk.yml b/config/locales/simple_form.uk.yml
index 812e02855..c192c0612 100644
--- a/config/locales/simple_form.uk.yml
+++ b/config/locales/simple_form.uk.yml
@@ -85,6 +85,7 @@ uk:
         ip: Введіть адресу IPv4 або IPv6. Ви можете блокувати цілі діапазони, використовуючи синтаксис CIDR. Будьте обережні, щоб не заблокувати себе!
         severities:
           no_access: Заблокувати доступ до всіх ресурсів
+          sign_up_block: Нові реєстрації будуть неможливі
           sign_up_requires_approval: Нові реєстрації потребуватимуть затвердження вами
         severity: Виберіть, що буде відбуватися з запитами з цієї IP
       rule:
@@ -219,6 +220,7 @@ uk:
         ip: IP
         severities:
           no_access: Заборонити доступ
+          sign_up_block: Блокувати реєстрацію
           sign_up_requires_approval: Обмеження реєстрації
         severity: Правило
       notification_emails:
diff --git a/config/locales/simple_form.vi.yml b/config/locales/simple_form.vi.yml
index 6e794a45a..24eda6195 100644
--- a/config/locales/simple_form.vi.yml
+++ b/config/locales/simple_form.vi.yml
@@ -85,6 +85,7 @@ vi:
         ip: Nhập một địa chỉ IPv4 hoặc IPv6. Bạn cũng có thể chặn toàn bộ dãy IP bằng cú pháp CIDR. Hãy cẩn thận đừng chặn nhầm toàn bộ!
         severities:
           no_access: Chặn truy cập từ tất cả IP này
+          sign_up_block: Không chấp nhận đăng ký mới
           sign_up_requires_approval: Bạn sẽ phê duyệt những đăng ký mới từ IP này
         severity: Chọn hành động nếu nhận được yêu cầu từ IP này
       rule:
@@ -219,6 +220,7 @@ vi:
         ip: IP
         severities:
           no_access: Chặn truy cập
+          sign_up_block: Chặn đăng ký
           sign_up_requires_approval: Giới hạn đăng ký
         severity: Mức độ
       notification_emails:
diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml
index eae4be245..645e8101d 100644
--- a/config/locales/simple_form.zh-CN.yml
+++ b/config/locales/simple_form.zh-CN.yml
@@ -85,6 +85,7 @@ zh-CN:
         ip: 输入 IPv4 或 IPv6 地址。你可以使用 CIDR 语法屏蔽 IP 段。小心不要屏蔽自己!
         severities:
           no_access: 阻止访问所有资源
+          sign_up_block: 无法进行新的账号注册
           sign_up_requires_approval: 新注册需要你的批准
         severity: 选择如何处理来自此 IP 的请求。
       rule:
@@ -219,6 +220,7 @@ zh-CN:
         ip: IP 地址
         severities:
           no_access: 阻止访问
+          sign_up_block: 阻止账号注册
           sign_up_requires_approval: 限制注册
         severity: 规则
       notification_emails:
diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml
index b4aef1bd2..9643752c5 100644
--- a/config/locales/simple_form.zh-TW.yml
+++ b/config/locales/simple_form.zh-TW.yml
@@ -85,6 +85,7 @@ zh-TW:
         ip: 請輸入 IPv4 或 IPv6 位址,亦可以用 CIDR 語法以封鎖整個 IP 區段。小心不要把自己給一併封鎖掉囉!
         severities:
           no_access: 封鎖對所有資源存取
+          sign_up_block: 無法註冊新帳號
           sign_up_requires_approval: 新註冊申請需要先經過您的審核
         severity: 請選擇將如何處理來自這個 IP 位址的請求
       rule:
@@ -219,6 +220,7 @@ zh-TW:
         ip: IP 位址
         severities:
           no_access: 封鎖
+          sign_up_block: 禁止註冊新帳號
           sign_up_requires_approval: 限制註冊
         severity: 規則
       notification_emails:
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 5fefb4e09..7b02930c2 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -110,6 +110,11 @@ sk:
         new_email: Nový email
         submit: Zmeň email
         title: Zmeň email pre %{username}
+      change_role:
+        changed_msg: Postavenie úspešne zmenené!
+        label: Zmeň pozíciu
+        no_role: Žiadna pozícia
+        title: Zmeň pozíciu pre %{username}
       confirm: Potvrď
       confirmed: Potvrdený
       confirming: Potvrdzujúci
@@ -146,6 +151,7 @@ sk:
         active: Aktívny/a
         all: Všetko
         pending: Čakajúci
+        silenced: Obmedzený
         suspended: Vylúčený/á
         title: Moderácia
       moderation_notes: Moderátorské poznámky
@@ -153,6 +159,7 @@ sk:
       most_recent_ip: Posledná IP adresa
       no_account_selected: Nedošlo k žiadnému pozmeneniu účtov, keďže žiadne neboli vybrané
       no_limits_imposed: Nie sú stanovené žiadné obmedzenia
+      no_role_assigned: Žiadne postavenie nepriradené
       not_subscribed: Neodoberá
       pending: Vyžaduje posúdenie
       perform_full_suspension: Vylúč
@@ -171,6 +178,7 @@ sk:
       reset: Resetuj
       reset_password: Obnov heslo
       resubscribe: Znovu odoberaj
+      role: Postavenie
       search: Hľadaj
       search_same_email_domain: Iní užívatelia s tou istou emailovou doménou
       search_same_ip: Ostatní užívatelia s rovnakou IP adresou
@@ -347,7 +355,9 @@ sk:
       domain: Doména
       new:
         create: Pridaj doménu
+        resolve: Preveď doménu
         title: Nový email na zablokovanie
+      resolved_through_html: Prevedená cez %{domain}
       title: Blokované emailové adresy
     follow_recommendations:
       description_html: "<strong>Odporúčania na sledovanie pomáhaju novým užívateľom rýchlo nájsť zaujímavý obsah</strong>. Ak užívateľ zatiaľ nedostatočne interagoval s ostatnými aby si vyformoval personalizované odporúčania na sledovanie, tak mu budú odporúčané tieto účty. Sú prepočítavané na dennej báze z mixu účtov s nedávnym najvyšším záujmom a najvyšším počtom lokálnych sledujúcich pre daný jazyk."
@@ -369,7 +379,11 @@ sk:
         policies:
           reject_media: Zamietni médiá
           suspend: Vylúč
+        policy: Zásady
         reason: Verejné odôvodnenie
+        title: Zásady o obsahu
+      dashboard:
+        instance_accounts_dimension: Najsledovanejšie účty
       delivery:
         all: Všetko
         unavailable: Nedostupné
@@ -467,6 +481,23 @@ sk:
       unassign: Odober
       unresolved: Nevyriešené
       updated_at: Aktualizované
+      view_profile: Zobraz profil
+    roles:
+      add_new: Pridaj postavenie
+      assigned_users:
+        few: "%{count} užívateľov"
+        many: "%{count} užívateľov"
+        one: "%{count} užívateľ"
+        other: "%{count} užívatelia"
+      categories:
+        administration: Spravovanie
+        invites: Pozvánky
+      edit: Uprav postavenie %{name}
+      privileges:
+        administrator: Správca
+        invite_users: Pozvi užívateľov
+        manage_roles: Spravuj postavenia
+      title: Postavenia
     rules:
       empty: Žiadne pravidlá servera ešte neboli určené.
       title: Serverové pravidlá
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index e4c510308..ea7b8e6ba 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -1221,6 +1221,8 @@ sl:
     edit:
       add_keyword: Dodaj ključno besedo
       keywords: Ključne besede
+      statuses: Posamezne objave
+      statuses_hint_html: Ta filter se nanaša na posamezne objave ne glede na to, ali se ujemajo s spodnjimi ključnimi besedami. Te objave lahko pregledate in jih odstranite iz filtra, če <a href="%{path}">kliknete tukaj</a>.
       title: Uredite filter
     errors:
       deprecated_api_multiple_keywords: Teh parametrov ni mogoče spremeniti iz tega programa, ker veljajo za več kot eno ključno besedo filtra. Uporabite novejšo izdaj programa ali spletni vmesnik.
@@ -1236,10 +1238,27 @@ sl:
         one: "%{count} ključna beseda"
         other: "%{count} ključnih besed"
         two: "%{count} ključni besedi"
+      statuses:
+        few: "%{count} objave"
+        one: "%{count} objava"
+        other: "%{count} objav"
+        two: "%{count} objavi"
+      statuses_long:
+        few: "%{count} posamezne objave skrite"
+        one: "%{count} posamezna objava skrita"
+        other: "%{count} posameznih objav skritih"
+        two: "%{count} posamezni objavi skriti"
       title: Filtri
     new:
       save: Shrani nov filter
       title: Dodaj nov filter
+    statuses:
+      back_to_filter: Nazaj na filter
+      batch:
+        remove: Odstrani iz filtra
+      index:
+        hint: Ta filter se nanaša na posamezne objave ne glede na druge pogoje. Filtru lahko dodate več objav prek spletnega vmesnika.
+        title: Filtrirane objave
   footer:
     developers: Razvijalci
     more: Več…
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 28ffeb462..7f3c25ff1 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -457,11 +457,11 @@ th:
         resolve: แปลงที่อยู่โดเมน
         title: ปิดกั้นโดเมนอีเมลใหม่
       no_email_domain_block_selected: ไม่มีการเปลี่ยนแปลงการปิดกั้นโดเมนอีเมลเนื่องจากไม่มีการเลือก
-      resolved_dns_records_hint_html: ชื่อโดเมนจะแก้ไขเป็นโดเมน MX ต่อไปนี้ ซึ่งแต่ท้ายที่สุดแล้วคุณจะต้องรับผิดชอบในการยอมรับอีเมล การบล็อกโดเมน MX จะบล็อกการลงชื่อสมัครใช้จากที่อยู่อีเมลใดๆ ที่ใช้โดเมน MX เดียวกัน ถึงแม้ว่าชื่อโดเมนที่มองเห็นได้นั้นจะต่างกัน <strong>ระวังอย่าบล็อกผู้ให้บริการอีเมลรายใหญ่</strong>
+      resolved_dns_records_hint_html: ชื่อโดเมนแปลงที่อยู่เป็นโดเมน MX ดังต่อไปนี้ ซึ่งท้ายที่สุดแล้วจะรับผิดชอบสำหรับการยอมรับอีเมล การปิดกั้นโดเมน MX จะปิดกั้นการลงทะเบียนจากที่อยู่อีเมลใด ๆ ซึ่งใช้โดเมน MX เดียวกัน แม้ว่าชื่อโดเมนที่ปรากฏจะแตกต่างกัน <strong>ระวังอย่าปิดกั้นผู้ให้บริการอีเมลรายใหญ่</strong>
       resolved_through_html: แปลงที่อยู่ผ่าน %{domain}
       title: โดเมนอีเมลที่ปิดกั้นอยู่
     follow_recommendations:
-      description_html: "<strong>จะทำตามคำแนะนำช่วยให้ผู้ใช้ใหม่ให้พบเนื้อหาที่น่าสนใจได้อย่างรวดเร็ว</strong> เมื่อผู้ใช้ไม่ได้โต้ตอบใดๆกับผู้อื่นมากพอที่จะสร้างคำแนะนำส่วนบุคคลให้กดติดตาม ขอแนะนำให้ใช้บัญชีเหล่านี้แทน พวกเขาจะคำนวณใหม่ทุกๆวันจากบัญชีต่างๆ ที่มีการมีส่วนร่วมล่าสุดและจำนวนผู้ติดตามในพื้นที่สูงสุดสำหรับภาษาที่คุณกำหนดไว้"
+      description_html: "<strong>คำแนะนำการติดตามช่วยให้ผู้ใช้ใหม่ค้นหาเนื้อหาที่น่าสนใจได้อย่างรวดเร็ว</strong> เมื่อผู้ใช้ไม่ได้โต้ตอบกับผู้อื่นมากพอที่จะสร้างคำแนะนำการติดตามส่วนบุคคล จะแนะนำบัญชีเหล่านี้แทน จะคำนวณคำแนะนำใหม่เป็นประจำทุกวันจากบัญชีต่าง ๆ ที่มีการมีส่วนร่วมล่าสุดสูงสุดและจำนวนผู้ติดตามในเซิร์ฟเวอร์สูงสุดสำหรับภาษาที่กำหนด"
       language: สำหรับภาษา
       status: สถานะ
       suppress: ระงับคำแนะนำการติดตาม
@@ -470,7 +470,14 @@ th:
       unsuppress: คืนค่าคำแนะนำการติดตาม
     instances:
       availability:
+        description_html:
+          other: หากการจัดส่งไปยังโดเมนล้มเหลวเป็นเวลา <strong>%{count} วันที่แตกต่างกัน</strong> โดยไม่สำเร็จ จะไม่ทำการพยายามจัดส่งเพิ่มเติมเว้นแต่จะได้รับการจัดส่ง <em>จาก</em> โดเมน
+        failure_threshold_reached: ถึงค่าเกณฑ์ความล้มเหลวเมื่อ %{date}
+        failures_recorded:
+          other: ความพยายามที่ล้มเหลวเป็นเวลา %{count} วันที่แตกต่างกัน
+        no_failures_recorded: ไม่มีความล้มเหลวในระเบียน
         title: ความพร้อมใช้งาน
+        warning: ความพยายามล่าสุดในการเชื่อมต่อกับเซิร์ฟเวอร์นี้ไม่สำเร็จ
       back_to_all: ทั้งหมด
       back_to_limited: จำกัดอยู่
       back_to_warning: คำเตือน
@@ -505,6 +512,8 @@ th:
         unavailable: ไม่พร้อมใช้งาน
       delivery_available: มีการจัดส่ง
       delivery_error_days: วันที่มีข้อผิดพลาดการจัดส่ง
+      delivery_error_hint: หากไม่สามารถทำการจัดส่งได้เป็นเวลา %{count} วัน จะทำเครื่องหมายโดเมนว่าจัดส่งไม่ได้โดยอัตโนมัติ
+      destroyed_msg: ตอนนี้จัดคิวข้อมูลจาก %{domain} สำหรับการลบในเร็ว ๆ นี้แล้ว
       empty: ไม่พบโดเมน
       known_accounts:
         other: "%{count} บัญชีที่รู้จัก"
@@ -515,12 +524,14 @@ th:
       private_comment: ความคิดเห็นส่วนตัว
       public_comment: ความคิดเห็นสาธารณะ
       purge: ล้างข้อมูล
+      purge_description_html: หากคุณเชื่อว่าโดเมนนี้ออฟไลน์อย่างถาวร คุณสามารถลบระเบียนบัญชีและข้อมูลที่เกี่ยวข้องทั้งหมดจากโดเมนนี้จากที่เก็บข้อมูลของคุณ นี่อาจใช้เวลาสักครู่
       title: การติดต่อกับภายนอก
       total_blocked_by_us: ปิดกั้นโดยเรา
       total_followed_by_them: ติดตามโดยเขา
       total_followed_by_us: ติดตามโดยเรา
       total_reported: รายงานเกี่ยวกับเขา
       total_storage: ไฟล์แนบสื่อ
+      totals_time_period_hint_html: ยอดรวมที่แสดงด้านล่างรวมข้อมูลสำหรับเวลาทั้งหมด
     invites:
       deactivate_all: ปิดใช้งานทั้งหมด
       filter:
@@ -549,6 +560,7 @@ th:
     relays:
       add_new: เพิ่มรีเลย์ใหม่
       delete: ลบ
+      description_html: "<strong>รีเลย์การติดต่อกับภายนอก</strong> เป็นเซิร์ฟเวอร์ตัวกลางที่แลกเปลี่ยนโพสต์สาธารณะจำนวนมากระหว่างเซิร์ฟเวอร์ที่บอกรับและเผยแพร่ไปยังรีเลย์ <strong>รีเลย์สามารถช่วยให้เซิร์ฟเวอร์ขนาดเล็กและขนาดกลางค้นพบเนื้อหาจากจักรวาลสหพันธ์</strong> ซึ่งมิฉะนั้นจะต้องให้ผู้ใช้ในเซิร์ฟเวอร์ติดตามผู้คนอื่น ๆ ในเซิร์ฟเวอร์ระยะไกลด้วยตนเอง"
       disable: ปิดใช้งาน
       disabled: ปิดใช้งานอยู่
       enable: เปิดใช้งาน
@@ -558,6 +570,7 @@ th:
       pending: กำลังรอการอนุมัติของรีเลย์
       save_and_enable: บันทึกแล้วเปิดใช้งาน
       setup: ตั้งค่าการเชื่อมต่อแบบรีเลย์
+      signatures_not_enabled: รีเลย์จะทำงานไม่ถูกต้องขณะที่มีการเปิดใช้งานโหมดปลอดภัยหรือโหมดการติดต่อกับภายนอกแบบจำกัด
       status: สถานะ
       title: รีเลย์
     report_notes:
@@ -571,9 +584,12 @@ th:
       action_log: รายการบันทึกการตรวจสอบ
       action_taken_by: ใช้การกระทำโดย
       actions:
+        delete_description_html: จะลบโพสต์ที่รายงานและจะบันทึกการดำเนินการเพื่อช่วยให้คุณเลื่อนระดับการละเมิดในอนาคตโดยบัญชีเดียวกัน
+        mark_as_sensitive_description_html: จะทำเครื่องหมายสื่อในโพสต์ที่รายงานว่าละเอียดอ่อนและจะบันทึกการดำเนินการเพื่อช่วยให้คุณเลื่อนระดับการละเมิดในอนาคตโดยบัญชีเดียวกัน
         other_description_html: ดูตัวเลือกเพิ่มเติมสำหรับการควบคุมพฤติกรรมของบัญชีและปรับแต่งการสื่อสารไปยังบัญชีที่รายงาน
         resolve_description_html: จะไม่ใช้การกระทำกับบัญชีที่รายงาน ไม่มีการบันทึกการดำเนินการ และจะปิดรายงาน
       actions_description_html: ตัดสินใจว่าการกระทำใดที่จะใช้เพื่อแก้ปัญหารายงานนี้ หากคุณใช้การกระทำที่เป็นการลงโทษกับบัญชีที่รายงาน จะส่งการแจ้งเตือนอีเมลถึงเขา ยกเว้นเมื่อมีการเลือกหมวดหมู่ <strong>สแปม</strong>
+      add_to_report: เพิ่มข้อมูลเพิ่มเติมไปยังรายงาน
       are_you_sure: คุณแน่ใจหรือไม่?
       assign_to_self: มอบหมายให้ฉัน
       assigned: ผู้ควบคุมที่ได้รับมอบหมาย
@@ -596,6 +612,7 @@ th:
         create_and_unresolve: เปิดใหม่โดยมีหมายเหตุ
         delete: ลบ
         title: หมายเหตุ
+      notes_description_html: ดูและฝากหมายเหตุถึงผู้ควบคุมอื่น ๆ และตัวคุณเองในอนาคต
       quick_actions_description_html: 'ดำเนินการอย่างรวดเร็วหรือเลื่อนลงเพื่อดูเนื้อหาที่รายงาน:'
       remote_user_placeholder: ผู้ใช้ระยะไกลจาก %{instance}
       reopen: เปิดรายงานใหม่
@@ -623,6 +640,7 @@ th:
         moderation: การควบคุม
         special: พิเศษ
       delete: ลบ
+      description_html: ด้วย <strong>บทบาทผู้ใช้</strong> คุณสามารถปรับแต่งว่าฟังก์ชันและพื้นที่ใดของ Mastodon ที่ผู้ใช้ของคุณสามารถเข้าถึง
       edit: แก้ไขบทบาท '%{name}'
       everyone: สิทธิอนุญาตเริ่มต้น
       permissions_count:
@@ -631,18 +649,33 @@ th:
         administrator: ผู้ดูแล
         delete_user_data: ลบข้อมูลผู้ใช้
         invite_users: เชิญผู้ใช้
+        invite_users_description: อนุญาตให้ผู้ใช้เชิญผู้คนใหม่ไปยังเซิร์ฟเวอร์
         manage_announcements: จัดการประกาศ
+        manage_announcements_description: อนุญาตให้ผู้ใช้จัดการประกาศในเซิร์ฟเวอร์
         manage_appeals: จัดการการอุทธรณ์
+        manage_appeals_description: อนุญาตให้ผู้ใช้ตรวจทานการอุทธรณ์ต่อการกระทำการควบคุม
         manage_blocks: จัดการการปิดกั้น
+        manage_blocks_description: อนุญาตให้ผู้ใช้ปิดกั้นผู้ให้บริการอีเมลและที่อยู่ IP
         manage_custom_emojis: จัดการอีโมจิที่กำหนดเอง
+        manage_custom_emojis_description: อนุญาตให้ผู้ใช้จัดการอีโมจิที่กำหนดเองในเซิร์ฟเวอร์
         manage_federation: จัดการการติดต่อกับภายนอก
+        manage_federation_description: อนุญาตให้ผู้ใช้ปิดกั้นหรืออนุญาตการติดต่อกับภายนอกกับโดเมนอื่น ๆ และควบคุมความสามารถในการจัดส่ง
         manage_invites: จัดการคำเชิญ
+        manage_invites_description: อนุญาตให้ผู้ใช้เรียกดูและปิดใช้งานลิงก์เชิญ
         manage_reports: จัดการรายงาน
         manage_roles: จัดการบทบาท
         manage_rules: จัดการกฎ
+        manage_rules_description: อนุญาตให้ผู้ใช้เปลี่ยนกฎของเซิร์ฟเวอร์
         manage_settings: จัดการการตั้งค่า
+        manage_settings_description: อนุญาตให้ผู้ใช้เปลี่ยนการตั้งค่าไซต์
+        manage_taxonomies: จัดการอนุกรมวิธาน
+        manage_taxonomies_description: อนุญาตให้ผู้ใช้ตรวจทานเนื้อหาที่กำลังนิยมและอัปเดตการตั้งค่าแฮชแท็ก
         manage_user_access: จัดการการเข้าถึงของผู้ใช้
         manage_users: จัดการผู้ใช้
+        view_audit_log: ดูรายการบันทึกการตรวจสอบ
+        view_audit_log_description: อนุญาตให้ผู้ใช้ดูประวัติการกระทำการดูแลในเซิร์ฟเวอร์
+        view_dashboard: ดูแดชบอร์ด
+        view_dashboard_description: อนุญาตให้ผู้ใช้เข้าถึงแดชบอร์ดและเมตริกต่าง ๆ
         view_devops_description: อนุญาตให้ผู้ใช้เข้าถึงแดชบอร์ด Sidekiq และ pgHero
       title: บทบาท
     rules:
@@ -795,6 +828,7 @@ th:
         allow_account: อนุญาตผู้สร้าง
         disallow: ไม่อนุญาตโพสต์
         disallow_account: ไม่อนุญาตผู้สร้าง
+        not_discoverable: ผู้สร้างไม่ได้เลือกรับให้สามารถค้นพบได้
         shared_by:
           other: แบ่งปันและชื่นชอบ %{friendly_count} ครั้ง
         title: โพสต์ที่กำลังนิยม
@@ -941,6 +975,7 @@ th:
       confirming: กำลังรอการยืนยันอีเมลให้เสร็จสมบูรณ์
       functional: บัญชีของคุณทำงานได้อย่างเต็มที่
       pending: ใบสมัครของคุณกำลังรอดำเนินการตรวจทานโดยพนักงานของเรา นี่อาจใช้เวลาสักครู่ คุณจะได้รับอีเมลหากใบสมัครของคุณได้รับการอนุมัติ
+      redirecting_to: บัญชีของคุณไม่ได้ใช้งานเนื่องจากบัญชีกำลังเปลี่ยนเส้นทางไปยัง %{acct} ในปัจจุบัน
       view_strikes: ดูการดำเนินการที่ผ่านมากับบัญชีของคุณ
     too_fast: ส่งแบบฟอร์มเร็วเกินไป ลองอีกครั้ง
     trouble_logging_in: มีปัญหาในการเข้าสู่ระบบ?
@@ -959,6 +994,7 @@ th:
     title: ติดตาม %{acct}
   challenge:
     confirm: ดำเนินการต่อ
+    hint_html: "<strong>เคล็ดลับ:</strong> เราจะไม่ถามรหัสผ่านของคุณกับคุณสำหรับชั่วโมงถัดไป"
     invalid_password: รหัสผ่านไม่ถูกต้อง
     prompt: ยืนยันรหัสผ่านเพื่อดำเนินการต่อ
   crypto:
@@ -1008,6 +1044,7 @@ th:
     strikes:
       action_taken: การกระทำที่ใช้
       appeal: อุทธรณ์
+      appeal_approved: อุทธรณ์การดำเนินการนี้สำเร็จและไม่มีผลบังคับอีกต่อไป
       appeal_rejected: ปฏิเสธการอุทธรณ์แล้ว
       appeal_submitted_at: ส่งการอุทธรณ์แล้ว
       appeals:
@@ -1119,6 +1156,7 @@ th:
       overwrite: เขียนทับ
       overwrite_long: แทนที่ระเบียนปัจจุบันด้วยระเบียนใหม่
     preface: คุณสามารถนำเข้าข้อมูลที่คุณได้ส่งออกจากเซิร์ฟเวอร์อื่น เช่น รายการผู้คนที่คุณกำลังติดตามหรือกำลังปิดกั้น
+    success: อัปโหลดข้อมูลของคุณสำเร็จและจะได้รับการประมวลผลในเวลาที่ครบกำหนด
     types:
       blocking: รายการปิดกั้น
       bookmarks: ที่คั่นหน้า
@@ -1170,6 +1208,7 @@ th:
     cancel_explanation: การยกเลิกการเปลี่ยนเส้นทางจะเปิดใช้งานบัญชีปัจจุบันของคุณใหม่ แต่จะไม่นำผู้ติดตามที่ได้รับการย้ายไปยังบัญชีนั้นกลับมา
     cancelled_msg: ยกเลิกการเปลี่ยนเส้นทางสำเร็จ
     errors:
+      already_moved: เป็นบัญชีเดียวกันกับที่คุณได้ย้ายไปแล้ว
       missing_also_known_as: ไม่ใช่นามแฝงของบัญชีนี้
       move_to_self: ไม่สามารถเป็นบัญชีปัจจุบัน
       not_found: ไม่พบ
@@ -1298,6 +1337,7 @@ th:
     status: สถานะบัญชี
   remote_follow:
     acct: ป้อน username@domain ของคุณที่คุณต้องการกระทำจาก
+    missing_resource: ไม่พบ URL การเปลี่ยนเส้นทางที่จำเป็นสำหรับบัญชีของคุณ
     no_account_html: ไม่มีบัญชี? คุณสามารถ <a href='%{sign_up_path}' target='_blank'>ลงทะเบียนที่นี่</a>
     proceed: ดำเนินการต่อเพื่อติดตาม
     prompt: 'คุณกำลังจะติดตาม:'
@@ -1318,6 +1358,7 @@ th:
     content_warning: 'คำเตือนเนื้อหา:'
     descriptions:
       account: โพสต์สาธารณะจาก @%{acct}
+      tag: 'โพสต์สาธารณะที่ได้รับการแท็ก #%{hashtag}'
   scheduled_statuses:
     too_soon: วันที่ตามกำหนดการต้องอยู่ในอนาคต
   sessions:
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index bc2b730f8..2706070a3 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -79,7 +79,7 @@ tr:
       following: Onaylamak istediğiniz kişiyi zaten takip ediyor olmalısınız
     posts:
       one: Gönderi
-      other: Toot
+      other: Gönderiler
     posts_tab_heading: Tootlar
     posts_with_replies: Tootlar ve yanıtlar
     roles:
@@ -1181,6 +1181,8 @@ tr:
     edit:
       add_keyword: Anahtar sözcük ekle
       keywords: Anahtar Sözcükler
+      statuses: Tekil gönderiler
+      statuses_hint_html: Bu filtre aşağıdaki anahtar kelimelere eşlenip eşlenmediklerinden bağımsız olarak tekil gönderileri seçmek için uygulanıyor. Bu gönderileri gözden geçirip, <a href="%{path}">buraya tıklayarak</a> filtreden kaldırabilirsiniz.
       title: Filtreyi düzenle
     errors:
       deprecated_api_multiple_keywords: Bu parametreler, birden fazla filtre anahtar sözcüğü için geçerli olduğundan dolayı bu uygulama içerisinden değiştirilemezler. Daha yeni bir uygulama veya web arayüzünü kullanın.
@@ -1194,10 +1196,23 @@ tr:
       keywords:
         one: "%{count} anahtar sözcük"
         other: "%{count} anahtar sözcük"
+      statuses:
+        one: "%{count} gönderi"
+        other: "%{count} gönderi"
+      statuses_long:
+        one: "%{count} tekil gönderi gizli"
+        other: "%{count} tekil gönderi gizli"
       title: Filtreler
     new:
       save: Yeni filtre kaydet
       title: Yeni filtre ekle
+    statuses:
+      back_to_filter: Filtreye dön
+      batch:
+        remove: Filtreden kaldır
+      index:
+        hint: Bu filtre diğer ölçütlerden bağımsız olarak tekil gönderileri seçmek için uygulanıyor. Web arayüzünü kullanarak bu filtreye daha fazla gönderi ekleyebilirsiniz.
+        title: Filtrelenmiş gönderiler
   footer:
     developers: Geliştiriciler
     more: Daha Fazla…
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index 708ce998e..c1ca26c52 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -513,6 +513,7 @@ uk:
       confirm_purge: Ви впевнені, що хочете видалити ці дані з цього домену?
       content_policies:
         comment: Внутрішня примітка
+        description_html: Ви можете визначити правила вмісту що буде застосовано до всіх облікових записів із цього домену та будь-якого з його піддоменів.
         policies:
           reject_media: Відхилити медіа
           reject_reports: Відхилити скарги
@@ -617,7 +618,10 @@ uk:
       action_log: Журнал подій
       action_taken_by: Дія виконана
       actions:
+        delete_description_html: Дописи, на які скаржилися будуть видалені, а попередження буде записано, щоб допомогти вам підвищити рівень майбутніх порушень того самого облікового запису.
+        mark_as_sensitive_description_html: Медіа у дописах, на які скаржилися будуть позначені делікатними, а попередження буде записано, щоб допомогти вам підвищити рівень майбутніх порушень того самого облікового запису.
         other_description_html: Більше опцій керування поведінкою облікового запису і налаштування комунікації з обліковим записом, на який поскаржилися.
+        resolve_description_html: Не буде застосовано жодних дій проти облікового запису, на який скаржилися, не буде записано попередження, а скаргу буде закрито.
         silence_description_html: Профіль буде видимий лише тим, хто вже стежить за ним або знайде його самостійно, сильно обмежуючи його знаходження. Можна потім скасувати.
         suspend_description_html: Профіль і весь його вміст буде недоступним, поки його не буде видалено. Взаємодія з обліковим записом буде неможливою.
       add_to_report: Додати ще подробиць до скарги
@@ -892,6 +896,7 @@ uk:
         allow_account: Дозволити автора
         disallow: Заборонити допис
         disallow_account: Заборонити автора
+        not_discoverable: Автор не вирішив бути видимим
         title: Популярні дописи
       tags:
         current_score: Поточний результат %{score}
@@ -967,14 +972,18 @@ uk:
       body_remote: Хтось з домену %{domain} поскаржився(-лася) на %{target}
       subject: Нова скарга до %{instance} (#%{id})
     new_trends:
+      body: 'Ці елементи потребують розгляду перед оприлюдненням:'
       new_trending_links:
         no_approved_links: На цей час немає схвалених популярних посилань.
+        requirements: 'Кожен з цих кандидатів може перевершити #%{rank} затвердженого популярного посилання, яке зараз на «%{lowest_link_title}» з рейтингом %{lowest_link_score}.'
         title: Популярні посилання
       new_trending_statuses:
         no_approved_statuses: На цей час немає схвалених популярних дописів.
+        requirements: 'Кожен з цих кандидатів може перевершити #%{rank} затвердженого популярного допису, який зараз на %{lowest_status_url} з рейтингом %{lowest_status_score}.'
         title: Популярні дописи
       new_trending_tags:
         no_approved_tags: На цей час немає схвалених популярних хештегів.
+        requirements: 'Кожен з цих кандидатів може перевершити #%{rank} затвердженого популярного хештеґу, який зараз на #%{lowest_tag_name} з рейтингом %{lowest_tag_score}.'
         title: Популярні хештеги
       subject: Нове популярне до розгляду на %{instance}
   aliases:
@@ -1129,6 +1138,7 @@ uk:
       approve_appeal: Схвалити апеляцію
       associated_report: Пов'язана скарга
       created_at: Застарілі
+      description_html: Це дії, виконані проти вашого облікового запису та попереджень, які були відправлені вам персоналом %{instance}.
       recipient: Адресант
       reject_appeal: Відхилити апеляцію
       status: 'Допис #%{id}'
@@ -1356,7 +1366,7 @@ uk:
       title: Поки ви були відсутні...
     favourite:
       body: 'Ваш статус подобається %{name}:'
-      subject: Користувачу %{name} сподобався ваш статус
+      subject: Ваш статус сподобався %{name}
       title: Нове вподобання
     follow:
       body: "%{name} тепер підписаний(-а) на вас!"
diff --git a/config/locales/vi.yml b/config/locales/vi.yml
index b471cc153..625d3a07e 100644
--- a/config/locales/vi.yml
+++ b/config/locales/vi.yml
@@ -915,7 +915,7 @@ vi:
         sensitive: đánh dấu tài khoản của họ là nhạy cảm
         silence: hạn chế tài khoản của họ
         suspend: vô hiệu hóa tài khoản của họ
-      body: "%{target} đã khiếu nại quyết định kiểm duyệt từ %{action_taken_by} vào %{date}, vì %{type}. Họ cho biết:"
+      body: "%{target} đã khiếu nại quyết định kiểm duyệt bởi %{action_taken_by} vào %{date}, vì %{type}. Họ cho biết:"
       next_steps: Bạn có thể chấp nhận kháng cáo để hủy bỏ kiểm duyệt, hoặc bỏ qua.
       subject: "%{username} đang khiếu nại quyết định kiểm duyệt trên %{instance}"
     new_pending_account:
@@ -1159,6 +1159,7 @@ vi:
     edit:
       add_keyword: Thêm từ khoá
       keywords: Từ khóa
+      statuses: Những tút riêng lẻ
       title: Chỉnh sửa bộ lọc
     errors:
       deprecated_api_multiple_keywords: Không thể thay đổi các tham số này từ ứng dụng này vì chúng áp dụng cho nhiều hơn một từ khóa bộ lọc. Sử dụng ứng dụng mới hơn hoặc giao diện web.
@@ -1171,10 +1172,18 @@ vi:
       expires_on: Hết hạn vào %{date}
       keywords:
         other: "%{count} từ khóa"
+      statuses:
+        other: "%{count} tút"
       title: Bộ lọc
     new:
       save: Lưu thành bộ lọc mới
       title: Thêm bộ lọc mới
+    statuses:
+      back_to_filter: Quay về bộ lọc
+      batch:
+        remove: Xóa khỏi bộ lọc
+      index:
+        title: Những tút đã lọc
   footer:
     developers: Phát triển
     more: Nhiều hơn
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 12b371bf3..1a71554bb 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -692,6 +692,7 @@ zh-CN:
         view_dashboard: 查看仪表板
         view_dashboard_description: 允许用户访问仪表盘和各种指标
         view_devops: 开发运维
+        view_devops_description: 允许用户访问 Sidekiq 和 pgHero 仪表板
       title: 角色
     rules:
       add_new: 添加规则
@@ -893,6 +894,7 @@ zh-CN:
       description_html: "<strong>webhook</strong> 使Mastodon能够推送 <strong>关于所选事件的实时通知</strong> 到您自己的应用程序。 所以您的应用程序可以自动触发反应 <strong></strong>。"
       disable: 禁用
       disabled: 已禁用
+      edit: 编辑端点
       empty: 您尚未配置任何Web 钩子端点。
       enable: 启用
       enabled: 活跃
@@ -1159,6 +1161,8 @@ zh-CN:
     edit:
       add_keyword: 添加关键词
       keywords: 关键词
+      statuses: 个别嘟文
+      statuses_hint_html: 无论是否匹配下列关键词,此过滤器适用于选用个别嘟文。你可以<a href="%{path}">点击此处</a>来审核这些嘟文,并从过滤器中移除。
       title: 编辑过滤器
     errors:
       deprecated_api_multiple_keywords: 这些参数不能从此应用程序更改,因为它们应用于一个以上的过滤关键字。 使用较新的应用程序或网页界面。
@@ -1171,10 +1175,21 @@ zh-CN:
       expires_on: "%{date} 后到期"
       keywords:
         other: "%{count} 关键词"
+      statuses:
+        other: "%{count} 条嘟文"
+      statuses_long:
+        other: "%{count} 条个别嘟文已隐藏"
       title: 过滤器
     new:
       save: 保存新过滤器
       title: 添加新的过滤器
+    statuses:
+      back_to_filter: 返回至过滤器
+      batch:
+        remove: 从过滤器中移除
+      index:
+        hint: 无论其他条件如何,此过滤器适用于选用个别嘟文。你可以从网页界面中向此过滤器加入更多嘟文。
+        title: 过滤的嘟文
   footer:
     developers: 开发者
     more: 更多…
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index 1490aeef1..c055ba69f 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -1163,6 +1163,8 @@ zh-TW:
     edit:
       add_keyword: 新增關鍵字
       keywords: 關鍵字
+      statuses: 各別嘟文
+      statuses_hint_html: 此過濾器會套用至所選之各別嘟文,不管它們有無匹配到以下的關鍵字。您可以檢視這些嘟文而<a href="%{path}">按此</a>將它們從過濾器中移除。
       title: 編輯篩選條件
     errors:
       deprecated_api_multiple_keywords: 這些參數無法從此應用程式中更改,因為它們適用於一或多個過濾器關鍵字。請使用較新的應用程式或是網頁介面。
@@ -1175,10 +1177,21 @@ zh-TW:
       expires_on: 於 %{date} 過期
       keywords:
         other: "%{count} 個關鍵字"
+      statuses:
+        other: "%{count} 則嘟文"
+      statuses_long:
+        other: "%{count} 則各別嘟文被隱藏"
       title: 過濾器
     new:
       save: 儲存新過濾器
       title: 新增篩選器
+    statuses:
+      back_to_filter: 回到過濾器
+      batch:
+        remove: 從過濾器中移除
+      index:
+        hint: 此過濾器會套用至所選之各別嘟文,不管它們有無符合其他條件。您可以從網頁介面中將更多嘟文加入至此過濾器。
+        title: 已過濾之嘟文
   footer:
     developers: 開發者
     more: 更多......
diff --git a/config/routes.rb b/config/routes.rb
index 52ba0956a..6057852c0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -180,7 +180,14 @@ Rails.application.routes.draw do
   resources :tags,   only: [:show]
   resources :emojis, only: [:show]
   resources :invites, only: [:index, :create, :destroy]
-  resources :filters, except: [:show]
+  resources :filters, except: [:show] do
+    resources :statuses, only: [:index], controller: 'filters/statuses' do
+      collection do
+        post :batch
+      end
+    end
+  end
+
   resource :relationships, only: [:show, :update]
   resource :statuses_cleanup, controller: :statuses_cleanup, only: [:show, :update]
 
@@ -470,12 +477,14 @@ Rails.application.routes.draw do
       resources :trends,       only: [:index], controller: 'trends/tags'
       resources :filters,      only: [:index, :create, :show, :update, :destroy] do
         resources :keywords, only: [:index, :create], controller: 'filters/keywords'
+        resources :statuses, only: [:index, :create], controller: 'filters/statuses'
       end
       resources :endorsements, only: [:index]
       resources :markers,      only: [:index, :create]
 
       namespace :filters do
         resources :keywords, only: [:show, :update, :destroy]
+        resources :statuses, only: [:show, :destroy]
       end
 
       namespace :apps do
diff --git a/db/migrate/20220808101323_create_custom_filter_statuses.rb b/db/migrate/20220808101323_create_custom_filter_statuses.rb
new file mode 100644
index 000000000..52f703749
--- /dev/null
+++ b/db/migrate/20220808101323_create_custom_filter_statuses.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class CreateCustomFilterStatuses < ActiveRecord::Migration[6.1]
+  def change
+    create_table :custom_filter_statuses do |t|
+      t.belongs_to :custom_filter, foreign_key: { on_delete: :cascade }, null: false
+      t.belongs_to :status, foreign_key: { on_delete: :cascade }, null: false
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 7a8262dfa..868303faf 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2022_07_14_171049) do
+ActiveRecord::Schema.define(version: 2022_08_08_101323) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -348,6 +348,15 @@ ActiveRecord::Schema.define(version: 2022_07_14_171049) do
     t.index ["custom_filter_id"], name: "index_custom_filter_keywords_on_custom_filter_id"
   end
 
+  create_table "custom_filter_statuses", force: :cascade do |t|
+    t.bigint "custom_filter_id", null: false
+    t.bigint "status_id", null: false
+    t.datetime "created_at", precision: 6, null: false
+    t.datetime "updated_at", precision: 6, null: false
+    t.index ["custom_filter_id"], name: "index_custom_filter_statuses_on_custom_filter_id"
+    t.index ["status_id"], name: "index_custom_filter_statuses_on_status_id"
+  end
+
   create_table "custom_filters", force: :cascade do |t|
     t.bigint "account_id"
     t.datetime "expires_at"
@@ -1116,6 +1125,8 @@ ActiveRecord::Schema.define(version: 2022_07_14_171049) do
   add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade
   add_foreign_key "conversation_mutes", "conversations", on_delete: :cascade
   add_foreign_key "custom_filter_keywords", "custom_filters", on_delete: :cascade
+  add_foreign_key "custom_filter_statuses", "custom_filters", on_delete: :cascade
+  add_foreign_key "custom_filter_statuses", "statuses", on_delete: :cascade
   add_foreign_key "custom_filters", "accounts", on_delete: :cascade
   add_foreign_key "devices", "accounts", on_delete: :cascade
   add_foreign_key "devices", "oauth_access_tokens", column: "access_token_id", on_delete: :cascade
diff --git a/lib/mastodon/accounts_cli.rb b/lib/mastodon/accounts_cli.rb
index 29c934453..558f4d3c4 100644
--- a/lib/mastodon/accounts_cli.rb
+++ b/lib/mastodon/accounts_cli.rb
@@ -57,7 +57,7 @@ module Mastodon
     option :role
     option :reattach, type: :boolean
     option :force, type: :boolean
-    desc 'create USERNAME', 'Create a new user'
+    desc 'create USERNAME', 'Create a new user account'
     long_desc <<-LONG_DESC
       Create a new user account with a given USERNAME and an
       e-mail address provided with --email.
@@ -133,7 +133,7 @@ module Mastodon
     option :disable_2fa, type: :boolean
     option :approve, type: :boolean
     option :reset_password, type: :boolean
-    desc 'modify USERNAME', 'Modify a user'
+    desc 'modify USERNAME', 'Modify a user account'
     long_desc <<-LONG_DESC
       Modify a user account.
 
diff --git a/lib/mastodon/media_cli.rb b/lib/mastodon/media_cli.rb
index 36ca71844..4904cc5eb 100644
--- a/lib/mastodon/media_cli.rb
+++ b/lib/mastodon/media_cli.rb
@@ -187,6 +187,7 @@ module Mastodon
     option :account, type: :string
     option :domain, type: :string
     option :status, type: :numeric
+    option :days, type: :numeric
     option :concurrency, type: :numeric, default: 5, aliases: [:c]
     option :verbose, type: :boolean, default: false, aliases: [:v]
     option :dry_run, type: :boolean, default: false
@@ -204,6 +205,8 @@ module Mastodon
 
       Use the --domain option to download attachments from a specific domain.
 
+      Use the --days option to limit attachments created within days.
+
       By default, attachments that are believed to be already downloaded will
       not be re-downloaded. To force re-download of every URL, use --force.
     DESC
@@ -224,10 +227,16 @@ module Mastodon
         scope = MediaAttachment.where(account_id: account.id)
       elsif options[:domain]
         scope = MediaAttachment.joins(:account).merge(Account.by_domain_and_subdomains(options[:domain]))
+      elsif options[:days].present?
+        scope = MediaAttachment.remote
       else
         exit(1)
       end
 
+      if options[:days].present?
+        scope = scope.where('id > ?', Mastodon::Snowflake.id_at(options[:days].days.ago, with_random: false))
+      end
+
       processed, aggregate = parallelize_with_progress(scope) do |media_attachment|
         next if media_attachment.remote_url.blank? || (!options[:force] && media_attachment.file_file_name.present?)
         next if DomainBlock.reject_media?(media_attachment.account.domain)
diff --git a/nanobox/nginx-local.conf b/nanobox/nginx-local.conf
deleted file mode 100644
index 37c8a451a..000000000
--- a/nanobox/nginx-local.conf
+++ /dev/null
@@ -1,92 +0,0 @@
-worker_processes 1;
-daemon off;
-
-events {
-    worker_connections 1024;
-}
-
-http {
-    include /data/etc/nginx/mime.types;
-    sendfile on;
-
-    gzip on;
-    gzip_disable "MSIE [1-6]\.";
-    gzip_vary on;
-    gzip_proxied any;
-    gzip_comp_level 6;
-    gzip_buffers 16 8k;
-    gzip_min_length 500;
-    gzip_http_version 1.1;
-    gzip_types text/plain text/xml text/javascript text/css text/comma-separated-values application/xml+rss application/xml application/x-javascript application/json application/javascript application/atom+xml;
-
-    # Proxy upstream to the puma process
-    upstream rails {
-        server 127.0.0.1:3000;
-    }
-
-    # Proxy upstream to the node process
-    upstream node {
-        server 127.0.0.1:4000;
-    }
-
-    map $http_upgrade $connection_upgrade {
-        default upgrade;
-        ''      close;
-    }
-
-    # Configuration for Nginx
-    server {
-        # Listen on port 8080
-        listen 8080;
-
-        keepalive_timeout    70;
-        client_max_body_size 80M;
-
-        root /app/public;
-
-        add_header Strict-Transport-Security "max-age=31536000";
-
-        location / {
-            try_files $uri @rails;
-        }
-
-        # Proxy connections to rails
-        location @rails {
-            proxy_set_header Host $host;
-            proxy_set_header X-Real-IP $remote_addr;
-            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-            proxy_set_header X-Forwarded-Proto https;
-            proxy_set_header Proxy "";
-            proxy_pass_header Server;
-
-            proxy_pass http://rails;
-            proxy_buffering off;
-            proxy_redirect off;
-            proxy_http_version 1.1;
-            proxy_set_header Upgrade $http_upgrade;
-            proxy_set_header Connection $connection_upgrade;
-
-            tcp_nodelay on;
-        }
-
-        # Proxy connections to node
-        location /api/v1/streaming {
-            proxy_set_header Host $host;
-            proxy_set_header X-Real-IP $remote_addr;
-            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-            proxy_set_header X-Forwarded-Proto https;
-            proxy_set_header Proxy "";
-
-            proxy_pass http://node;
-            proxy_buffering off;
-            proxy_redirect off;
-            proxy_http_version 1.1;
-            proxy_set_header Upgrade $http_upgrade;
-            proxy_set_header Connection $connection_upgrade;
-
-            tcp_nodelay on;
-        }
-    }
-
-    error_page 500 501 502 503 504 /500.html;
-}
diff --git a/nanobox/nginx-stream.conf.erb b/nanobox/nginx-stream.conf.erb
deleted file mode 100644
index 4ea6e30fc..000000000
--- a/nanobox/nginx-stream.conf.erb
+++ /dev/null
@@ -1,66 +0,0 @@
-worker_processes 1;
-daemon off;
-
-events {
-    worker_connections 1024;
-}
-
-http {
-    include /data/etc/nginx/mime.types;
-    sendfile on;
-
-    gzip on;
-    gzip_disable "MSIE [1-6]\.";
-    gzip_vary on;
-    gzip_proxied any;
-    gzip_comp_level 6;
-    gzip_buffers 16 8k;
-    gzip_min_length 500;
-    gzip_http_version 1.1;
-    gzip_types text/plain text/xml text/javascript text/css text/comma-separated-values application/xml+rss application/xml application/x-javascript application/json application/javascript application/atom+xml;
-
-    # Proxy upstream to the node process
-    upstream node {
-        server 127.0.0.1:4000;
-    }
-
-    map $http_upgrade $connection_upgrade {
-        default upgrade;
-        ''      close;
-    }
-
-    # Configuration for Nginx
-    server {
-        # Listen on port 8080
-        listen 8080;
-
-        keepalive_timeout    70;
-        client_max_body_size 80M;
-
-        root /app/public;
-
-        add_header Strict-Transport-Security "max-age=31536000";
-
-        location / {
-            try_files $uri @node;
-        }
-
-        # Proxy connections to node
-        location @node {
-            proxy_set_header Host $host;
-            proxy_set_header X-Real-IP $remote_addr;
-            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-            proxy_set_header X-Forwarded-Proto https;
-            proxy_set_header Proxy "";
-
-            proxy_pass http://node;
-            proxy_buffering off;
-            proxy_redirect off;
-            proxy_http_version 1.1;
-            proxy_set_header Upgrade $http_upgrade;
-            proxy_set_header Connection $connection_upgrade;
-
-            tcp_nodelay on;
-        }
-    }
-}
diff --git a/nanobox/nginx-web.conf.erb b/nanobox/nginx-web.conf.erb
deleted file mode 100644
index 182d99209..000000000
--- a/nanobox/nginx-web.conf.erb
+++ /dev/null
@@ -1,90 +0,0 @@
-worker_processes 1;
-daemon off;
-
-events {
-    worker_connections 1024;
-}
-
-http {
-    include /data/etc/nginx/mime.types;
-    sendfile on;
-
-    gzip on;
-    gzip_disable "MSIE [1-6]\.";
-    gzip_vary on;
-    gzip_proxied any;
-    gzip_comp_level 6;
-    gzip_buffers 16 8k;
-    gzip_min_length 500;
-    gzip_http_version 1.1;
-    gzip_types text/plain text/xml text/javascript text/css text/comma-separated-values application/xml+rss application/xml application/x-javascript application/json application/javascript application/atom+xml;
-
-    # Proxy upstream to the puma process
-    upstream rails {
-        server 127.0.0.1:3000;
-    }
-
-    map $http_upgrade $connection_upgrade {
-        default upgrade;
-        ''      close;
-    }
-
-    # Configuration for Nginx
-    server {
-        # Listen on port 8080
-        listen 8080;
-
-        keepalive_timeout    70;
-        client_max_body_size 80M;
-
-        root /app/public;
-
-        add_header Strict-Transport-Security "max-age=31536000";
-
-        location / {
-            try_files $uri @rails;
-        }
-
-        location /sw.js {
-            add_header Cache-Control "public, max-age=0";
-            add_header Strict-Transport-Security "max-age=31536000";
-            try_files $uri @rails;
-        }
-
-        location ~ ^/(emoji|packs|system/media_attachments/files|system/accounts/avatars) {
-            add_header Cache-Control "public, max-age=31536000, immutable";
-            add_header Strict-Transport-Security "max-age=31536000";
-            try_files $uri @rails;
-        }
-
-        # Proxy connections to rails
-        location @rails {
-            proxy_set_header Host $host;
-            proxy_set_header X-Real-IP $remote_addr;
-            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-            proxy_set_header X-Forwarded-Proto https;
-            proxy_set_header Proxy "";
-            proxy_pass_header Server;
-
-            proxy_pass http://rails;
-            proxy_buffering on;
-            proxy_redirect off;
-            proxy_http_version 1.1;
-            proxy_set_header Upgrade $http_upgrade;
-            proxy_set_header Connection $connection_upgrade;
-
-            proxy_cache CACHE;
-            proxy_cache_valid 200 7d;
-            proxy_cache_valid 410 24h;
-            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
-            add_header Strict-Transport-Security "max-age=31536000";
-            add_header X-Cached $upstream_cache_status;
-
-            tcp_nodelay on;
-        }
-    }
-
-    proxy_cache_path /data/var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;
-
-    error_page 500 501 502 503 504 /500.html;
-}
diff --git a/package.json b/package.json
index 9b5ad7c4c..f1417c9cc 100644
--- a/package.json
+++ b/package.json
@@ -24,11 +24,11 @@
   },
   "private": true,
   "dependencies": {
-    "@babel/core": "^7.18.9",
-    "@babel/plugin-proposal-decorators": "^7.18.9",
+    "@babel/core": "^7.18.13",
+    "@babel/plugin-proposal-decorators": "^7.18.10",
     "@babel/plugin-transform-react-inline-elements": "^7.18.6",
-    "@babel/plugin-transform-runtime": "^7.18.9",
-    "@babel/preset-env": "^7.18.9",
+    "@babel/plugin-transform-runtime": "^7.18.10",
+    "@babel/preset-env": "^7.18.10",
     "@babel/preset-react": "^7.18.6",
     "@babel/runtime": "^7.18.9",
     "@gamestdio/websocket": "^0.3.2",
@@ -47,7 +47,7 @@
     "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
     "blurhash": "^1.1.5",
     "classnames": "^2.3.1",
-    "cocoon-js-vanilla": "^1.2.0",
+    "cocoon-js-vanilla": "^1.3.0",
     "color-blend": "^3.0.1",
     "compression-webpack-plugin": "^6.1.1",
     "cross-env": "^7.0.3",
@@ -88,7 +88,7 @@
     "offline-plugin": "^5.0.7",
     "path-complete-extname": "^1.0.0",
     "pg": "^8.5.0",
-    "postcss": "^8.4.14",
+    "postcss": "^8.4.16",
     "postcss-loader": "^3.0.0",
     "postcss-object-fit-images": "^1.1.2",
     "promise.prototype.finally": "^3.1.3",
@@ -122,7 +122,7 @@
     "requestidlecallback": "^0.3.0",
     "reselect": "^4.1.6",
     "rimraf": "^3.0.2",
-    "sass": "^1.54.0",
+    "sass": "^1.54.5",
     "sass-loader": "^10.2.0",
     "stacktrace-js": "^2.0.2",
     "stringz": "^2.1.0",
@@ -135,7 +135,7 @@
     "uuid": "^8.3.1",
     "webpack": "^4.46.0",
     "webpack-assets-manifest": "^4.0.6",
-    "webpack-bundle-analyzer": "^4.5.0",
+    "webpack-bundle-analyzer": "^4.6.1",
     "webpack-cli": "^3.3.12",
     "webpack-merge": "^5.8.0",
     "wicg-inert": "^3.1.2",
@@ -143,7 +143,7 @@
   },
   "devDependencies": {
     "@babel/eslint-parser": "^7.18.9",
-    "@testing-library/jest-dom": "^5.16.4",
+    "@testing-library/jest-dom": "^5.16.5",
     "@testing-library/react": "^12.1.5",
     "babel-jest": "^28.1.3",
     "eslint": "^7.32.0",
@@ -158,7 +158,7 @@
     "raf": "^3.4.1",
     "react-intl-translations-manager": "^5.0.3",
     "react-test-renderer": "^16.14.0",
-    "stylelint": "^14.9.1",
+    "stylelint": "^14.11.0",
     "stylelint-config-standard-scss": "^4.0.0",
     "webpack-dev-server": "^3.11.3",
     "yargs": "^17.5.1"
diff --git a/spec/controllers/api/v1/filters/statuses_controller_spec.rb b/spec/controllers/api/v1/filters/statuses_controller_spec.rb
new file mode 100644
index 000000000..3b2399dd8
--- /dev/null
+++ b/spec/controllers/api/v1/filters/statuses_controller_spec.rb
@@ -0,0 +1,116 @@
+require 'rails_helper'
+
+RSpec.describe Api::V1::Filters::StatusesController, type: :controller do
+  render_views
+
+  let(:user)         { Fabricate(:user) }
+  let(:token)        { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+  let(:filter)       { Fabricate(:custom_filter, account: user.account) }
+  let(:other_user)   { Fabricate(:user) }
+  let(:other_filter) { Fabricate(:custom_filter, account: other_user.account) }
+
+  before do
+    allow(controller).to receive(:doorkeeper_token) { token }
+  end
+
+  describe 'GET #index' do
+    let(:scopes) { 'read:filters' }
+    let!(:status_filter) { Fabricate(:custom_filter_status, custom_filter: filter) }
+
+    it 'returns http success' do
+      get :index, params: { filter_id: filter.id }
+      expect(response).to have_http_status(200)
+    end
+
+    context "when trying to access another's user filters" do
+      it 'returns http not found' do
+        get :index, params: { filter_id: other_filter.id }
+        expect(response).to have_http_status(404)
+      end
+    end
+  end
+
+  describe 'POST #create' do
+    let(:scopes)    { 'write:filters' }
+    let(:filter_id) { filter.id }
+    let!(:status)   { Fabricate(:status) }
+
+    before do
+      post :create, params: { filter_id: filter_id, status_id: status.id }
+    end
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+
+    it 'returns a status filter' do
+      json = body_as_json
+      expect(json[:status_id]).to eq status.id.to_s
+    end
+
+    it 'creates a status filter' do
+      filter = user.account.custom_filters.first
+      expect(filter).to_not be_nil
+      expect(filter.statuses.pluck(:status_id)).to eq [status.id]
+    end
+
+    context "when trying to add to another another's user filters" do
+      let(:filter_id) { other_filter.id }
+
+      it 'returns http not found' do
+        expect(response).to have_http_status(404)
+      end
+    end
+  end
+
+  describe 'GET #show' do
+    let(:scopes)  { 'read:filters' }
+    let!(:status_filter) { Fabricate(:custom_filter_status, custom_filter: filter) }
+
+    before do
+      get :show, params: { id: status_filter.id }
+    end
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+
+    it 'returns expected data' do
+      json = body_as_json
+      expect(json[:status_id]).to eq status_filter.status_id.to_s
+    end
+
+    context "when trying to access another user's filter keyword" do
+      let(:status_filter) { Fabricate(:custom_filter_status, custom_filter: other_filter) }
+
+      it 'returns http not found' do
+        expect(response).to have_http_status(404)
+      end
+    end
+  end
+
+  describe 'DELETE #destroy' do
+    let(:scopes)  { 'write:filters' }
+    let(:status_filter) { Fabricate(:custom_filter_status, custom_filter: filter) }
+
+    before do
+      delete :destroy, params: { id: status_filter.id }
+    end
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+
+    it 'removes the filter' do
+      expect { status_filter.reload }.to raise_error ActiveRecord::RecordNotFound
+    end
+
+    context "when trying to update another user's filter keyword" do
+      let(:status_filter) { Fabricate(:custom_filter_status, custom_filter: other_filter) }
+
+      it 'returns http not found' do
+        expect(response).to have_http_status(404)
+      end
+    end
+  end
+end
diff --git a/spec/controllers/api/v1/statuses_controller_spec.rb b/spec/controllers/api/v1/statuses_controller_spec.rb
index 4d104a198..24810a5d2 100644
--- a/spec/controllers/api/v1/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses_controller_spec.rb
@@ -47,6 +47,33 @@ RSpec.describe Api::V1::StatusesController, type: :controller do
         end
       end
 
+      context 'when post is explicitly filtered' do
+        let(:status) { Fabricate(:status, text: 'hello world') }
+
+        before do
+          filter = user.account.custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide)
+          filter.statuses.create!(status_id: status.id)
+        end
+
+        it 'returns http success' do
+          get :show, params: { id: status.id }
+          expect(response).to have_http_status(200)
+        end
+
+        it 'returns filter information' do
+          get :show, params: { id: status.id }
+          json = body_as_json
+          expect(json[:filtered][0]).to include({
+            filter: a_hash_including({
+              id: user.account.custom_filters.first.id.to_s,
+              title: 'filter1',
+              filter_action: 'hide',
+            }),
+            status_matches: [status.id.to_s],
+          })
+        end
+      end
+
       context 'when reblog includes filtered terms' do
         let(:status) { Fabricate(:status, reblog: Fabricate(:status, text: 'this toot is about that banned word')) }
 
diff --git a/spec/fabricators/custom_filter_status_fabricator.rb b/spec/fabricators/custom_filter_status_fabricator.rb
new file mode 100644
index 000000000..d082b81c5
--- /dev/null
+++ b/spec/fabricators/custom_filter_status_fabricator.rb
@@ -0,0 +1,4 @@
+Fabricator(:custom_filter_status) do
+  custom_filter
+  status
+end
diff --git a/spec/fabricators/webauthn_credential_fabricator.rb b/spec/fabricators/webauthn_credential_fabricator.rb
index 496a7a735..ba59ce967 100644
--- a/spec/fabricators/webauthn_credential_fabricator.rb
+++ b/spec/fabricators/webauthn_credential_fabricator.rb
@@ -1,7 +1,7 @@
 Fabricator(:webauthn_credential) do
   user_id { Fabricate(:user).id }
   external_id { Base64.urlsafe_encode64(SecureRandom.random_bytes(16)) }
-  public_key { OpenSSL::PKey::EC.new("prime256v1").generate_key.public_key }
+  public_key { OpenSSL::PKey::EC.generate('prime256v1').public_key }
   nickname 'USB key'
   sign_count 0
 end
diff --git a/spec/models/email_domain_block_spec.rb b/spec/models/email_domain_block_spec.rb
index 567a32c32..e23116888 100644
--- a/spec/models/email_domain_block_spec.rb
+++ b/spec/models/email_domain_block_spec.rb
@@ -12,16 +12,29 @@ RSpec.describe EmailDomainBlock, type: :model do
     let(:input) { nil }
 
     context 'given an e-mail address' do
-      let(:input) { 'nyarn@example.com' }
+      let(:input) { "foo@#{domain}" }
 
-      it 'returns true if the domain is blocked' do
-        Fabricate(:email_domain_block, domain: 'example.com')
-        expect(EmailDomainBlock.block?(input)).to be true
+      context do
+        let(:domain) { 'example.com' }
+
+        it 'returns true if the domain is blocked' do
+          Fabricate(:email_domain_block, domain: 'example.com')
+          expect(EmailDomainBlock.block?(input)).to be true
+        end
+
+        it 'returns false if the domain is not blocked' do
+          Fabricate(:email_domain_block, domain: 'other-example.com')
+          expect(EmailDomainBlock.block?(input)).to be false
+        end
       end
 
-      it 'returns false if the domain is not blocked' do
-        Fabricate(:email_domain_block, domain: 'other-example.com')
-        expect(EmailDomainBlock.block?(input)).to be false
+      context do
+        let(:domain) { 'mail.example.com' }
+
+        it 'returns true if it is a subdomain of a blocked domain' do
+          Fabricate(:email_domain_block, domain: 'example.com')
+          expect(described_class.block?(input)).to be true
+        end
       end
     end
 
diff --git a/spec/presenters/status_relationships_presenter_spec.rb b/spec/presenters/status_relationships_presenter_spec.rb
index 5cd4929a6..eaab922fd 100644
--- a/spec/presenters/status_relationships_presenter_spec.rb
+++ b/spec/presenters/status_relationships_presenter_spec.rb
@@ -94,5 +94,32 @@ RSpec.describe StatusRelationshipsPresenter do
         expect(matched_filters[0].keyword_matches).to eq ['irrelevant']
       end
     end
+
+    context 'when post includes filtered individual statuses' do
+      let(:statuses) { [Fabricate(:status, text: 'hello world'), Fabricate(:status, reblog: Fabricate(:status, text: 'this toot is about an irrelevant word'))] }
+      let(:options) { {} }
+
+      before do
+        filter = Account.find(current_account_id).custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide)
+        filter.statuses.create!(status_id: statuses[0].id)
+        filter.statuses.create!(status_id: statuses[1].reblog_of_id)
+      end
+
+      it 'sets @filters_map to filter top-level status' do
+        matched_filters = presenter.filters_map[statuses[0].id]
+        expect(matched_filters.size).to eq 1
+
+        expect(matched_filters[0].filter.title).to eq 'filter1'
+        expect(matched_filters[0].status_matches).to eq [statuses[0].id]
+      end
+
+      it 'sets @filters_map to filter reblogged status' do
+        matched_filters = presenter.filters_map[statuses[1].reblog_of_id]
+        expect(matched_filters.size).to eq 1
+
+        expect(matched_filters[0].filter.title).to eq 'filter1'
+        expect(matched_filters[0].status_matches).to eq [statuses[1].reblog_of_id]
+      end
+    end
   end
 end
diff --git a/spec/services/app_sign_up_service_spec.rb b/spec/services/app_sign_up_service_spec.rb
index e0c83b704..8ec4d4a7a 100644
--- a/spec/services/app_sign_up_service_spec.rb
+++ b/spec/services/app_sign_up_service_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe AppSignUpService, type: :service do
     it 'returns nil when registrations are closed' do
       tmp = Setting.registrations_mode
       Setting.registrations_mode = 'none'
-      expect(subject.call(app, remote_ip, good_params)).to be_nil
+      expect { subject.call(app, remote_ip, good_params) }.to raise_error Mastodon::NotPermittedError
       Setting.registrations_mode = tmp
     end
 
diff --git a/yarn.lock b/yarn.lock
index 4e87843b6..ef01413a4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,11 @@
 # yarn lockfile v1
 
 
+"@adobe/css-tools@^4.0.1":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.0.1.tgz#b38b444ad3aa5fedbb15f2f746dcd934226a12dd"
+  integrity sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==
+
 "@ampproject/remapping@^2.1.0":
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34"
@@ -23,26 +28,26 @@
   dependencies:
     "@babel/highlight" "^7.18.6"
 
-"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.18.8":
+"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8":
   version "7.18.8"
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d"
   integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==
 
-"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.18.9", "@babel/core@^7.7.2":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.9.tgz#805461f967c77ff46c74ca0460ccf4fe933ddd59"
-  integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==
+"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.18.13", "@babel/core@^7.7.2":
+  version "7.18.13"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.13.tgz#9be8c44512751b05094a4d3ab05fc53a47ce00ac"
+  integrity sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==
   dependencies:
     "@ampproject/remapping" "^2.1.0"
     "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.18.9"
+    "@babel/generator" "^7.18.13"
     "@babel/helper-compilation-targets" "^7.18.9"
     "@babel/helper-module-transforms" "^7.18.9"
     "@babel/helpers" "^7.18.9"
-    "@babel/parser" "^7.18.9"
-    "@babel/template" "^7.18.6"
-    "@babel/traverse" "^7.18.9"
-    "@babel/types" "^7.18.9"
+    "@babel/parser" "^7.18.13"
+    "@babel/template" "^7.18.10"
+    "@babel/traverse" "^7.18.13"
+    "@babel/types" "^7.18.13"
     convert-source-map "^1.7.0"
     debug "^4.1.0"
     gensync "^1.0.0-beta.2"
@@ -58,12 +63,12 @@
     eslint-visitor-keys "^2.1.0"
     semver "^6.3.0"
 
-"@babel/generator@^7.18.9", "@babel/generator@^7.7.2":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.9.tgz#68337e9ea8044d6ddc690fb29acae39359cca0a5"
-  integrity sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==
+"@babel/generator@^7.18.13", "@babel/generator@^7.7.2":
+  version "7.18.13"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.13.tgz#59550cbb9ae79b8def15587bdfbaa388c4abf212"
+  integrity sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==
   dependencies:
-    "@babel/types" "^7.18.9"
+    "@babel/types" "^7.18.13"
     "@jridgewell/gen-mapping" "^0.3.2"
     jsesc "^2.5.1"
 
@@ -90,7 +95,7 @@
     "@babel/helper-annotate-as-pure" "^7.18.6"
     "@babel/types" "^7.18.6"
 
-"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.18.9":
+"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9":
   version "7.18.9"
   resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf"
   integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==
@@ -121,15 +126,13 @@
     "@babel/helper-annotate-as-pure" "^7.18.6"
     regexpu-core "^5.1.0"
 
-"@babel/helper-define-polyfill-provider@^0.3.1":
-  version "0.3.1"
-  resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz"
-  integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==
+"@babel/helper-define-polyfill-provider@^0.3.2":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz#bd10d0aca18e8ce012755395b05a79f45eca5073"
+  integrity sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==
   dependencies:
-    "@babel/helper-compilation-targets" "^7.13.0"
-    "@babel/helper-module-imports" "^7.12.13"
-    "@babel/helper-plugin-utils" "^7.13.0"
-    "@babel/traverse" "^7.13.0"
+    "@babel/helper-compilation-targets" "^7.17.7"
+    "@babel/helper-plugin-utils" "^7.16.7"
     debug "^4.1.1"
     lodash.debounce "^4.0.8"
     resolve "^1.14.2"
@@ -210,7 +213,7 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
   version "7.18.9"
   resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f"
   integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==
@@ -225,6 +228,16 @@
     "@babel/helper-wrap-function" "^7.18.6"
     "@babel/types" "^7.18.6"
 
+"@babel/helper-remap-async-to-generator@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519"
+  integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.18.6"
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-wrap-function" "^7.18.9"
+    "@babel/types" "^7.18.9"
+
 "@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9":
   version "7.18.9"
   resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz#1092e002feca980fbbb0bd4d51b74a65c6a500e6"
@@ -257,6 +270,11 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
+"@babel/helper-string-parser@^7.18.10":
+  version "7.18.10"
+  resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56"
+  integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==
+
 "@babel/helper-validator-identifier@^7.12.11":
   version "7.12.11"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
@@ -282,6 +300,16 @@
     "@babel/traverse" "^7.18.6"
     "@babel/types" "^7.18.6"
 
+"@babel/helper-wrap-function@^7.18.9":
+  version "7.18.10"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.10.tgz#a7fcd3ab9b1be4c9b52cf7d7fdc1e88c2ce93396"
+  integrity sha512-95NLBP59VWdfK2lyLKe6eTMq9xg+yWKzxzxbJ1wcYNi1Auz200+83fMDADjRxBvc2QQor5zja2yTQzXGhk2GtQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.18.9"
+    "@babel/template" "^7.18.10"
+    "@babel/traverse" "^7.18.10"
+    "@babel/types" "^7.18.10"
+
 "@babel/helpers@^7.18.9":
   version "7.18.9"
   resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9"
@@ -309,10 +337,10 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.6", "@babel/parser@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.9.tgz#f2dde0c682ccc264a9a8595efd030a5cc8fd2539"
-  integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.13":
+  version "7.18.13"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.13.tgz#5b2dd21cae4a2c5145f1fbd8ca103f9313d3b7e4"
+  integrity sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==
 
 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
   version "7.18.6"
@@ -330,14 +358,14 @@
     "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
     "@babel/plugin-proposal-optional-chaining" "^7.18.9"
 
-"@babel/plugin-proposal-async-generator-functions@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz#aedac81e6fc12bb643374656dd5f2605bf743d17"
-  integrity sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==
+"@babel/plugin-proposal-async-generator-functions@^7.18.10":
+  version "7.18.10"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz#85ea478c98b0095c3e4102bff3b67d306ed24952"
+  integrity sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==
   dependencies:
-    "@babel/helper-environment-visitor" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/helper-remap-async-to-generator" "^7.18.6"
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-remap-async-to-generator" "^7.18.9"
     "@babel/plugin-syntax-async-generators" "^7.8.4"
 
 "@babel/plugin-proposal-class-properties@^7.18.6":
@@ -357,10 +385,10 @@
     "@babel/helper-plugin-utils" "^7.18.6"
     "@babel/plugin-syntax-class-static-block" "^7.14.5"
 
-"@babel/plugin-proposal-decorators@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.9.tgz#d09d41ffc74af8499d2ac706ed0dbd5474711665"
-  integrity sha512-KD7zDNaD14CRpjQjVbV4EnH9lsKYlcpUrhZH37ei2IY+AlXrfAPy5pTmRUE4X6X1k8EsKXPraykxeaogqQvSGA==
+"@babel/plugin-proposal-decorators@^7.18.10":
+  version "7.18.10"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.10.tgz#788650d01e518a8a722eb8b3055dd9d73ecb7a35"
+  integrity sha512-wdGTwWF5QtpTY/gbBtQLAiCnoxfD4qMbN87NYZle1dOZ9Os8Y6zXcKrIaOU8W+TIvFUWVGG9tUgNww3CjXRVVw==
   dependencies:
     "@babel/helper-create-class-features-plugin" "^7.18.9"
     "@babel/helper-plugin-utils" "^7.18.9"
@@ -859,16 +887,16 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-runtime@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.9.tgz#d9e4b1b25719307bfafbf43065ed7fb3a83adb8f"
-  integrity sha512-wS8uJwBt7/b/mzE13ktsJdmS4JP/j7PQSaADtnb4I2wL0zK51MQ0pmF8/Jy0wUIS96fr+fXT6S/ifiPXnvrlSg==
+"@babel/plugin-transform-runtime@^7.18.10":
+  version "7.18.10"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz#37d14d1fa810a368fd635d4d1476c0154144a96f"
+  integrity sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==
   dependencies:
     "@babel/helper-module-imports" "^7.18.6"
     "@babel/helper-plugin-utils" "^7.18.9"
-    babel-plugin-polyfill-corejs2 "^0.3.1"
-    babel-plugin-polyfill-corejs3 "^0.5.2"
-    babel-plugin-polyfill-regenerator "^0.3.1"
+    babel-plugin-polyfill-corejs2 "^0.3.2"
+    babel-plugin-polyfill-corejs3 "^0.5.3"
+    babel-plugin-polyfill-regenerator "^0.4.0"
     semver "^6.3.0"
 
 "@babel/plugin-transform-shorthand-properties@^7.18.6":
@@ -907,12 +935,12 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.18.9"
 
-"@babel/plugin-transform-unicode-escapes@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz#0d01fb7fb2243ae1c033f65f6e3b4be78db75f27"
-  integrity sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw==
+"@babel/plugin-transform-unicode-escapes@^7.18.10":
+  version "7.18.10"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246"
+  integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.9"
 
 "@babel/plugin-transform-unicode-regex@^7.18.6":
   version "7.18.6"
@@ -922,10 +950,10 @@
     "@babel/helper-create-regexp-features-plugin" "^7.18.6"
     "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/preset-env@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.9.tgz#9b3425140d724fbe590322017466580844c7eaff"
-  integrity sha512-75pt/q95cMIHWssYtyfjVlvI+QEZQThQbKvR9xH+F/Agtw/s4Wfc2V9Bwd/P39VtixB7oWxGdH4GteTTwYJWMg==
+"@babel/preset-env@^7.18.10":
+  version "7.18.10"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.10.tgz#83b8dfe70d7eea1aae5a10635ab0a5fe60dfc0f4"
+  integrity sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==
   dependencies:
     "@babel/compat-data" "^7.18.8"
     "@babel/helper-compilation-targets" "^7.18.9"
@@ -933,7 +961,7 @@
     "@babel/helper-validator-option" "^7.18.6"
     "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6"
     "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9"
-    "@babel/plugin-proposal-async-generator-functions" "^7.18.6"
+    "@babel/plugin-proposal-async-generator-functions" "^7.18.10"
     "@babel/plugin-proposal-class-properties" "^7.18.6"
     "@babel/plugin-proposal-class-static-block" "^7.18.6"
     "@babel/plugin-proposal-dynamic-import" "^7.18.6"
@@ -993,13 +1021,13 @@
     "@babel/plugin-transform-sticky-regex" "^7.18.6"
     "@babel/plugin-transform-template-literals" "^7.18.9"
     "@babel/plugin-transform-typeof-symbol" "^7.18.9"
-    "@babel/plugin-transform-unicode-escapes" "^7.18.6"
+    "@babel/plugin-transform-unicode-escapes" "^7.18.10"
     "@babel/plugin-transform-unicode-regex" "^7.18.6"
     "@babel/preset-modules" "^0.1.5"
-    "@babel/types" "^7.18.9"
-    babel-plugin-polyfill-corejs2 "^0.3.1"
-    babel-plugin-polyfill-corejs3 "^0.5.2"
-    babel-plugin-polyfill-regenerator "^0.3.1"
+    "@babel/types" "^7.18.10"
+    babel-plugin-polyfill-corejs2 "^0.3.2"
+    babel-plugin-polyfill-corejs3 "^0.5.3"
+    babel-plugin-polyfill-regenerator "^0.4.0"
     core-js-compat "^3.22.1"
     semver "^6.3.0"
 
@@ -1055,36 +1083,37 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
-"@babel/template@^7.18.6", "@babel/template@^7.3.3":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"
-  integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==
+"@babel/template@^7.18.10", "@babel/template@^7.18.6", "@babel/template@^7.3.3":
+  version "7.18.10"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
+  integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==
   dependencies:
     "@babel/code-frame" "^7.18.6"
-    "@babel/parser" "^7.18.6"
-    "@babel/types" "^7.18.6"
+    "@babel/parser" "^7.18.10"
+    "@babel/types" "^7.18.10"
 
-"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.6", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.9.tgz#deeff3e8f1bad9786874cb2feda7a2d77a904f98"
-  integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==
+"@babel/traverse@^7.18.10", "@babel/traverse@^7.18.13", "@babel/traverse@^7.18.6", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2":
+  version "7.18.13"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.13.tgz#5ab59ef51a997b3f10c4587d648b9696b6cb1a68"
+  integrity sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==
   dependencies:
     "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.18.9"
+    "@babel/generator" "^7.18.13"
     "@babel/helper-environment-visitor" "^7.18.9"
     "@babel/helper-function-name" "^7.18.9"
     "@babel/helper-hoist-variables" "^7.18.6"
     "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/parser" "^7.18.9"
-    "@babel/types" "^7.18.9"
+    "@babel/parser" "^7.18.13"
+    "@babel/types" "^7.18.13"
     debug "^4.1.0"
     globals "^11.1.0"
 
-"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f"
-  integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==
+"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.18.10", "@babel/types@^7.18.13", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
+  version "7.18.13"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.13.tgz#30aeb9e514f4100f7c1cb6e5ba472b30e48f519a"
+  integrity sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==
   dependencies:
+    "@babel/helper-string-parser" "^7.18.10"
     "@babel/helper-validator-identifier" "^7.18.6"
     to-fast-properties "^2.0.0"
 
@@ -1093,10 +1122,10 @@
   resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
   integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
 
-"@csstools/selector-specificity@^2.0.1":
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.1.tgz#b6b8d81780b9a9f6459f4bfe9226ac6aefaefe87"
-  integrity sha512-aG20vknL4/YjQF9BSV7ts4EWm/yrjagAN7OWBNmlbEOUiu0llj4OGrFoOKK3g2vey4/p2omKCoHrWtPxSwV3HA==
+"@csstools/selector-specificity@^2.0.2":
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36"
+  integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
 
 "@emotion/babel-plugin@^11.7.1":
   version "11.9.2"
@@ -1621,16 +1650,16 @@
     lz-string "^1.4.4"
     pretty-format "^27.0.2"
 
-"@testing-library/jest-dom@^5.16.4":
-  version "5.16.4"
-  resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.4.tgz#938302d7b8b483963a3ae821f1c0808f872245cd"
-  integrity sha512-Gy+IoFutbMQcky0k+bqqumXZ1cTGswLsFqmNLzNdSKkU9KGV2u9oXhukCbbJ9/LRPKiqwxEE8VpV/+YZlfkPUA==
+"@testing-library/jest-dom@^5.16.5":
+  version "5.16.5"
+  resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz#3912846af19a29b2dbf32a6ae9c31ef52580074e"
+  integrity sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==
   dependencies:
+    "@adobe/css-tools" "^4.0.1"
     "@babel/runtime" "^7.9.2"
     "@types/testing-library__jest-dom" "^5.9.1"
     aria-query "^5.0.0"
     chalk "^3.0.0"
-    css "^3.0.0"
     css.escape "^1.5.1"
     dom-accessibility-api "^0.5.6"
     lodash "^4.17.15"
@@ -2122,12 +2151,7 @@ acorn@^7.1.1, acorn@^7.4.0:
   resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
   integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
 
-acorn@^8.0.4:
-  version "8.3.0"
-  resolved "https://registry.npmjs.org/acorn/-/acorn-8.3.0.tgz"
-  integrity sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==
-
-acorn@^8.5.0, acorn@^8.7.1:
+acorn@^8.0.4, acorn@^8.5.0, acorn@^8.7.1:
   version "8.7.1"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
   integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
@@ -2566,29 +2590,29 @@ babel-plugin-macros@^3.0.1:
     cosmiconfig "^7.0.0"
     resolve "^1.19.0"
 
-babel-plugin-polyfill-corejs2@^0.3.1:
-  version "0.3.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5"
-  integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==
+babel-plugin-polyfill-corejs2@^0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz#e4c31d4c89b56f3cf85b92558954c66b54bd972d"
+  integrity sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==
   dependencies:
-    "@babel/compat-data" "^7.13.11"
-    "@babel/helper-define-polyfill-provider" "^0.3.1"
+    "@babel/compat-data" "^7.17.7"
+    "@babel/helper-define-polyfill-provider" "^0.3.2"
     semver "^6.1.1"
 
-babel-plugin-polyfill-corejs3@^0.5.2:
-  version "0.5.2"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72"
-  integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==
+babel-plugin-polyfill-corejs3@^0.5.3:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz#d7e09c9a899079d71a8b670c6181af56ec19c5c7"
+  integrity sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==
   dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.3.1"
+    "@babel/helper-define-polyfill-provider" "^0.3.2"
     core-js-compat "^3.21.0"
 
-babel-plugin-polyfill-regenerator@^0.3.1:
-  version "0.3.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990"
-  integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==
+babel-plugin-polyfill-regenerator@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz#8f51809b6d5883e07e71548d75966ff7635527fe"
+  integrity sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw==
   dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.3.1"
+    "@babel/helper-define-polyfill-provider" "^0.3.2"
 
 babel-plugin-preval@^5.1.0:
   version "5.1.0"
@@ -3265,13 +3289,6 @@ clone-deep@^4.0.1:
     kind-of "^6.0.2"
     shallow-clone "^3.0.0"
 
-clone-regexp@^2.1.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f"
-  integrity sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==
-  dependencies:
-    is-regexp "^2.0.0"
-
 cluster-key-slot@1.1.0:
   version "1.1.0"
   resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz"
@@ -3291,10 +3308,10 @@ coa@^2.0.2:
     chalk "^2.4.1"
     q "^1.1.2"
 
-cocoon-js-vanilla@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/cocoon-js-vanilla/-/cocoon-js-vanilla-1.2.0.tgz#595348499d315d3b5828dd77a20974756cf59321"
-  integrity sha512-qLomIVL0Krfc983WLgaYPPktMjMtBN+F/CV15NPVDc9U9BCe2OL5WyAIYkPrVhDRphoYBmHCdIlZkq+vSBI4xg==
+cocoon-js-vanilla@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/cocoon-js-vanilla/-/cocoon-js-vanilla-1.3.0.tgz#1e53663f5d314e5e9b315b63eaf8ae701df113c0"
+  integrity sha512-rMnbfW6oFhvELUg141vfqZKzsowfLJRxs5FksfmDr1ZBs6LTNVYE63NQyvgRqyYUOK54cKKbI+V83dQKeeRuPg==
 
 collect-v8-coverage@^1.0.0:
   version "1.0.1"
@@ -3359,10 +3376,10 @@ color@^3.0.0:
     color-convert "^1.9.3"
     color-string "^1.6.0"
 
-colord@^2.9.2:
-  version "2.9.2"
-  resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1"
-  integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==
+colord@^2.9.3:
+  version "2.9.3"
+  resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
+  integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
 
 colorette@^1.2.2:
   version "1.4.0"
@@ -3755,15 +3772,6 @@ css.escape@^1.5.1:
   resolved "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz"
   integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=
 
-css@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.npmjs.org/css/-/css-3.0.0.tgz"
-  integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==
-  dependencies:
-    inherits "^2.0.4"
-    source-map "^0.6.1"
-    source-map-resolve "^0.6.0"
-
 cssesc@^3.0.0:
   version "3.0.0"
   resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
@@ -4757,13 +4765,6 @@ execa@^5.0.0:
     signal-exit "^3.0.3"
     strip-final-newline "^2.0.0"
 
-execall@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45"
-  integrity sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==
-  dependencies:
-    clone-regexp "^2.1.0"
-
 exif-js@^2.3.0:
   version "2.3.0"
   resolved "https://registry.npmjs.org/exif-js/-/exif-js-2.3.0.tgz"
@@ -4904,10 +4905,10 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
   resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
   integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
 
-fastest-levenshtein@^1.0.12:
-  version "1.0.12"
-  resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
-  integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
+fastest-levenshtein@^1.0.16:
+  version "1.0.16"
+  resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
+  integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
 
 fastq@^1.6.0:
   version "1.13.0"
@@ -5237,11 +5238,6 @@ get-package-type@^0.1.0:
   resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz"
   integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
 
-get-stdin@^8.0.0:
-  version "8.0.0"
-  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53"
-  integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==
-
 get-stream@^4.0.0:
   version "4.1.0"
   resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz"
@@ -6251,11 +6247,6 @@ is-regex@^1.1.4:
     call-bind "^1.0.2"
     has-tostringtag "^1.0.0"
 
-is-regexp@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d"
-  integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==
-
 is-resolvable@^1.0.0:
   version "1.1.0"
   resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz"
@@ -8758,10 +8749,10 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.27, postcss@^7.0.32:
     picocolors "^0.2.1"
     source-map "^0.6.1"
 
-postcss@^8.2.15, postcss@^8.4.14:
-  version "8.4.14"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
-  integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
+postcss@^8.2.15, postcss@^8.4.16:
+  version "8.4.16"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c"
+  integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==
   dependencies:
     nanoid "^3.3.4"
     picocolors "^1.0.0"
@@ -9730,10 +9721,10 @@ sass-loader@^10.2.0:
     schema-utils "^3.0.0"
     semver "^7.3.2"
 
-sass@^1.54.0:
-  version "1.54.0"
-  resolved "https://registry.yarnpkg.com/sass/-/sass-1.54.0.tgz#24873673265e2a4fe3d3a997f714971db2fba1f4"
-  integrity sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ==
+sass@^1.54.5:
+  version "1.54.5"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.54.5.tgz#93708f5560784f6ff2eab8542ade021a4a947b3a"
+  integrity sha512-p7DTOzxkUPa/63FU0R3KApkRHwcVZYC0PLnLm5iyZACyp15qSi32x7zVUhRdABAATmkALqgGrjCJAcWvobmhHw==
   dependencies:
     chokidar ">=3.0.0 <4.0.0"
     immutable "^4.0.0"
@@ -10096,14 +10087,6 @@ source-map-resolve@^0.5.0:
     source-map-url "^0.4.0"
     urix "^0.1.0"
 
-source-map-resolve@^0.6.0:
-  version "0.6.0"
-  resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz"
-  integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==
-  dependencies:
-    atob "^2.1.2"
-    decode-uri-component "^0.2.0"
-
 source-map-support@0.5.13:
   version "0.5.13"
   resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
@@ -10507,22 +10490,20 @@ stylelint-scss@^4.0.0:
     postcss-selector-parser "^6.0.6"
     postcss-value-parser "^4.1.0"
 
-stylelint@^14.9.1:
-  version "14.9.1"
-  resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.9.1.tgz#6494ed38f148b1e75b402d678a3b6a8aae86dfda"
-  integrity sha512-RdAkJdPiLqHawCSnu21nE27MjNXaVd4WcOHA4vK5GtIGjScfhNnaOuWR2wWdfKFAvcWQPOYe311iveiVKSmwsA==
+stylelint@^14.11.0:
+  version "14.11.0"
+  resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.11.0.tgz#e2ecb28bbacab05e1fbeb84cbba23883b27499cc"
+  integrity sha512-OTLjLPxpvGtojEfpESWM8Ir64Z01E89xsisaBMUP/ngOx1+4VG2DPRcUyCCiin9Rd3kPXPsh/uwHd9eqnvhsYA==
   dependencies:
-    "@csstools/selector-specificity" "^2.0.1"
+    "@csstools/selector-specificity" "^2.0.2"
     balanced-match "^2.0.0"
-    colord "^2.9.2"
+    colord "^2.9.3"
     cosmiconfig "^7.0.1"
     css-functions-list "^3.1.0"
     debug "^4.3.4"
-    execall "^2.0.0"
     fast-glob "^3.2.11"
-    fastest-levenshtein "^1.0.12"
+    fastest-levenshtein "^1.0.16"
     file-entry-cache "^6.0.1"
-    get-stdin "^8.0.0"
     global-modules "^2.0.0"
     globby "^11.1.0"
     globjoin "^0.1.4"
@@ -10537,7 +10518,7 @@ stylelint@^14.9.1:
     micromatch "^4.0.5"
     normalize-path "^3.0.0"
     picocolors "^1.0.0"
-    postcss "^8.4.14"
+    postcss "^8.4.16"
     postcss-media-query-parser "^0.2.3"
     postcss-resolve-nested-selector "^0.1.1"
     postcss-safe-parser "^6.0.0"
@@ -10551,7 +10532,7 @@ stylelint@^14.9.1:
     svg-tags "^1.0.0"
     table "^6.8.0"
     v8-compile-cache "^2.3.0"
-    write-file-atomic "^4.0.1"
+    write-file-atomic "^4.0.2"
 
 stylis@4.0.13:
   version "4.0.13"
@@ -11338,10 +11319,10 @@ webpack-assets-manifest@^4.0.6:
     tapable "^1.0"
     webpack-sources "^1.0"
 
-webpack-bundle-analyzer@^4.5.0:
-  version "4.5.0"
-  resolved "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz"
-  integrity sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==
+webpack-bundle-analyzer@^4.6.1:
+  version "4.6.1"
+  resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.6.1.tgz#bee2ee05f4ba4ed430e4831a319126bb4ed9f5a6"
+  integrity sha512-oKz9Oz9j3rUciLNfpGFjOb49/jEpXNmWdVH8Ls//zNcnLlQdTGXQQMsBbb/gR7Zl8WNLxVCq+0Hqbx3zv6twBw==
   dependencies:
     acorn "^8.0.4"
     acorn-walk "^8.0.0"
@@ -11605,10 +11586,10 @@ wrappy@1:
   resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
   integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
 
-write-file-atomic@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.1.tgz#9faa33a964c1c85ff6f849b80b42a88c2c537c8f"
-  integrity sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==
+write-file-atomic@^4.0.1, write-file-atomic@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd"
+  integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==
   dependencies:
     imurmurhash "^0.1.4"
     signal-exit "^3.0.7"