about summary refs log tree commit diff
path: root/config
diff options
context:
space:
mode:
Diffstat (limited to 'config')
-rw-r--r--config/application.rb6
-rw-r--r--config/environments/production.rb16
-rw-r--r--config/i18n-tasks.yml3
-rw-r--r--config/initializers/0_duplicate_migrations.rb52
-rw-r--r--config/initializers/content_security_policy.rb64
-rw-r--r--config/initializers/cors.rb4
-rw-r--r--config/initializers/locale.rb7
-rw-r--r--config/initializers/simple_form.rb10
-rw-r--r--config/locales-glitch/en.yml25
-rw-r--r--config/locales-glitch/es.yml25
-rw-r--r--config/locales-glitch/ja.yml6
-rw-r--r--config/locales-glitch/pl.yml6
-rw-r--r--config/locales-glitch/simple_form.en.yml20
-rw-r--r--config/locales-glitch/simple_form.es.yml20
-rw-r--r--config/locales-glitch/simple_form.ja.yml6
-rw-r--r--config/locales-glitch/simple_form.pl.yml10
-rwxr-xr-xconfig/locales/en-cafe.yml18
-rw-r--r--config/locales/simple_form.ar.yml1
-rw-r--r--config/locales/simple_form.ast.yml1
-rw-r--r--config/locales/simple_form.ca.yml1
-rw-r--r--config/locales/simple_form.co.yml1
-rw-r--r--config/locales/simple_form.cs.yml1
-rw-r--r--config/locales/simple_form.cy.yml1
-rw-r--r--config/locales/simple_form.da.yml1
-rw-r--r--config/locales/simple_form.de.yml1
-rw-r--r--config/locales/simple_form.el.yml1
-rw-r--r--config/locales/simple_form.en.yml3
-rw-r--r--config/locales/simple_form.eo.yml1
-rw-r--r--config/locales/simple_form.es-AR.yml1
-rw-r--r--config/locales/simple_form.es.yml1
-rw-r--r--config/locales/simple_form.et.yml1
-rw-r--r--config/locales/simple_form.eu.yml1
-rw-r--r--config/locales/simple_form.fa.yml1
-rw-r--r--config/locales/simple_form.fi.yml1
-rw-r--r--config/locales/simple_form.fr.yml1
-rw-r--r--config/locales/simple_form.gl.yml1
-rw-r--r--config/locales/simple_form.hu.yml1
-rw-r--r--config/locales/simple_form.hy.yml1
-rw-r--r--config/locales/simple_form.id.yml1
-rw-r--r--config/locales/simple_form.is.yml1
-rw-r--r--config/locales/simple_form.it.yml1
-rw-r--r--config/locales/simple_form.ja.yml1
-rw-r--r--config/locales/simple_form.kab.yml1
-rw-r--r--config/locales/simple_form.kk.yml1
-rw-r--r--config/locales/simple_form.ko.yml1
-rw-r--r--config/locales/simple_form.nl.yml1
-rw-r--r--config/locales/simple_form.nn.yml1
-rw-r--r--config/locales/simple_form.no.yml1
-rw-r--r--config/locales/simple_form.oc.yml1
-rw-r--r--config/locales/simple_form.pl.yml1
-rw-r--r--config/locales/simple_form.pt-BR.yml1
-rw-r--r--config/locales/simple_form.pt-PT.yml1
-rw-r--r--config/locales/simple_form.ro.yml1
-rw-r--r--config/locales/simple_form.ru.yml1
-rw-r--r--config/locales/simple_form.sk.yml1
-rw-r--r--config/locales/simple_form.sl.yml1
-rw-r--r--config/locales/simple_form.sq.yml1
-rw-r--r--config/locales/simple_form.sv.yml1
-rw-r--r--config/locales/simple_form.th.yml1
-rw-r--r--config/locales/simple_form.tr.yml1
-rw-r--r--config/locales/simple_form.uk.yml1
-rw-r--r--config/locales/simple_form.vi.yml1
-rw-r--r--config/locales/simple_form.zh-CN.yml1
-rw-r--r--config/locales/simple_form.zh-HK.yml1
-rw-r--r--config/locales/simple_form.zh-TW.yml1
-rw-r--r--config/navigation.rb6
-rw-r--r--config/routes.rb6
-rw-r--r--config/settings.yml17
-rw-r--r--config/themes.yml3
-rw-r--r--config/webpack/configuration.js57
-rw-r--r--config/webpack/generateLocalePacks.js94
-rw-r--r--config/webpack/rules/babel.js1
-rw-r--r--config/webpack/rules/css.js3
-rw-r--r--config/webpack/shared.js75
-rw-r--r--config/webpacker.yml1
75 files changed, 433 insertions, 178 deletions
diff --git a/config/application.rb b/config/application.rb
index af7735221..c85d4af06 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -60,6 +60,7 @@ module Mastodon
       :de,
       :el,
       :en,
+      :'en-cafe',
       :eo,
       :es,
       :'es-AR',
@@ -125,9 +126,12 @@ module Mastodon
     config.i18n.default_locale = ENV['DEFAULT_LOCALE']&.to_sym
 
     unless config.i18n.available_locales.include?(config.i18n.default_locale)
-      config.i18n.default_locale = :en
+      config.i18n.default_locale = :'en-cafe'
     end
 
+    # fall back to English when a translation cannot be found
+    config.i18n.fallbacks = [:'en-cafe', :en]
+
     # config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
     # config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
 
diff --git a/config/environments/production.rb b/config/environments/production.rb
index aaad2449f..bdda469ba 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -58,10 +58,6 @@ Rails.application.configure do
   # Set this to true and configure the email server for immediate delivery to raise delivery errors.
   # config.action_mailer.raise_delivery_errors = false
 
-  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
-  # English when a translation cannot be found).
-  config.i18n.fallbacks = [:en]
-
   # Send deprecation notices to registered listeners.
   config.active_support.deprecation = :notify
 
@@ -105,10 +101,14 @@ Rails.application.configure do
   config.action_mailer.delivery_method = ENV.fetch('SMTP_DELIVERY_METHOD', 'smtp').to_sym
 
   config.action_dispatch.default_headers = {
-    'Server'                 => 'Mastodon',
-    'X-Frame-Options'        => 'DENY',
-    'X-Content-Type-Options' => 'nosniff',
-    'X-XSS-Protection'       => '1; mode=block',
+    'Server'                  => 'Mastodon',
+    #'X-Frame-Options'         => 'DENY',
+    #'X-Content-Type-Options'  => 'nosniff',
+    #'X-XSS-Protection'        => '1; mode=block',
+    #'Referrer-Policy'         => 'same-origin',
+    #'Strict-Transport-Security' => 'max-age=63072000; includeSubDomains; preload',
+    'X-Clacks-Overhead' => 'GNU Natalie Nguyen'
+
   }
 
   config.x.otp_secret = ENV.fetch('OTP_SECRET')
diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml
index 2dc6f880b..3db1bc602 100644
--- a/config/i18n-tasks.yml
+++ b/config/i18n-tasks.yml
@@ -51,7 +51,7 @@ ignore_unused:
   - 'activerecord.errors.*'
   - '{devise,pagination,doorkeeper}.*'
   - '{date,datetime,time,number}.*'
-  - 'simple_form.{yes,no,recommended}'
+  - 'simple_form.{yes,no}'
   - 'simple_form.{placeholders,hints,labels}.*'
   - 'simple_form.{error_notification,required}.:'
   - 'errors.messages.*'
@@ -59,6 +59,7 @@ ignore_unused:
   - 'errors.429'
   - 'admin.accounts.roles.*'
   - 'admin.action_logs.actions.*'
+  - 'themes.*'
   - 'statuses.attached.*'
   - 'move_handler.carry_{mutes,blocks}_over_text'
 
diff --git a/config/initializers/0_duplicate_migrations.rb b/config/initializers/0_duplicate_migrations.rb
new file mode 100644
index 000000000..194aff70c
--- /dev/null
+++ b/config/initializers/0_duplicate_migrations.rb
@@ -0,0 +1,52 @@
+# Some migrations have been present in glitch-soc for a long time and have then
+# been merged in upstream Mastodon, under a different version number.
+#
+# This puts us in an uneasy situation in which if we remove upstream's
+# migration file, people migrating from upstream will end up having a conflict
+# with their already-ran migration.
+#
+# On the other hand, if we keep upstream's migration and remove our own,
+# any current glitch-soc user will have a conflict during migration.
+#
+# For lack of a better solution, as those migrations are indeed identical,
+# we decided monkey-patching Rails' Migrator to completely ignore the duplicate,
+# keeping only the one that has run, or an arbitrary one.
+
+ALLOWED_DUPLICATES = [20180410220657, 20180831171112].freeze
+
+module ActiveRecord
+  class Migrator
+    def self.new(direction, migrations, target_version = nil)
+      migrated = Set.new(Base.connection.migration_context.get_all_versions)
+
+      migrations.group_by(&:name).each do |name, duplicates|
+        if duplicates.length > 1 && duplicates.all? { |m| ALLOWED_DUPLICATES.include?(m.version) }
+          # We have a set of allowed duplicates. Keep the migrated one, if any.
+          non_migrated = duplicates.reject { |m| migrated.include?(m.version.to_i) }
+
+          if duplicates.length == non_migrated.length || non_migrated.length == 0
+            # There weren't any migrated one, so we have to pick one “canonical” migration
+            migrations = migrations - duplicates[1..-1]
+          else
+            # Just reject every duplicate which hasn't been migrated yet
+            migrations = migrations - non_migrated
+          end
+        end
+      end
+
+      super(direction, migrations, target_version)
+    end
+  end
+
+  class MigrationContext
+    def needs_migration?
+      # A set of duplicated migrations is considered migrated if at least one of
+      # them is migrated.
+      migrated = get_all_versions
+      migrations.group_by(&:name).each do |name, duplicates|
+        return true unless duplicates.any? { |m| migrated.include?(m.version.to_i) }
+      end
+      return false
+    end
+  end
+end
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
index 98dc711e1..a0d48eafd 100644
--- a/config/initializers/content_security_policy.rb
+++ b/config/initializers/content_security_policy.rb
@@ -2,43 +2,45 @@
 # For further information see the following documentation
 # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
 
-def host_to_url(str)
-  "http#{Rails.configuration.x.use_https ? 's' : ''}://#{str}" unless str.blank?
-end
+if Rails.env.production?
+  assets_host = Rails.configuration.action_controller.asset_host || "https://#{ENV['WEB_DOMAIN'] || ENV['LOCAL_DOMAIN']}"
+  data_hosts = [assets_host]
 
-base_host = Rails.configuration.x.web_domain
+  if ENV['S3_ENABLED'] == 'true'
+    attachments_host = "https://#{ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST'] || ENV['S3_HOSTNAME'] || "s3-#{ENV['S3_REGION'] || 'us-east-1'}.amazonaws.com"}"
+    attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}"
+  elsif ENV['SWIFT_ENABLED'] == 'true'
+    attachments_host = ENV['SWIFT_OBJECT_URL']
+    attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}"
+  else
+    attachments_host = nil
+  end
 
-assets_host   = Rails.configuration.action_controller.asset_host
-assets_host ||= host_to_url(base_host)
+  data_hosts << attachments_host unless attachments_host.nil?
 
-media_host   = host_to_url(ENV['S3_ALIAS_HOST'])
-media_host ||= host_to_url(ENV['S3_CLOUDFRONT_HOST'])
-media_host ||= host_to_url(ENV['S3_HOSTNAME']) if ENV['S3_ENABLED'] == 'true'
-media_host ||= assets_host
+  if ENV['PAPERCLIP_ROOT_URL']
+    url = Addressable::URI.parse(assets_host) + ENV['PAPERCLIP_ROOT_URL']
+    data_hosts << "https://#{url.host}"
+  end
 
-Rails.application.config.content_security_policy do |p|
-  p.base_uri        :none
-  p.default_src     :none
-  p.frame_ancestors :none
-  p.font_src        :self, assets_host
-  p.img_src         :self, :https, :data, :blob, assets_host
-  p.style_src       :self, assets_host
-  p.media_src       :self, :https, :data, assets_host
-  p.frame_src       :self, :https
-  p.manifest_src    :self, assets_host
+  data_hosts.concat(ENV['EXTRA_DATA_HOSTS'].split('|')) if ENV['EXTRA_DATA_HOSTS']
 
-  if Rails.env.development?
-    webpacker_urls = %w(ws http).map { |protocol| "#{protocol}#{Webpacker.dev_server.https? ? 's' : ''}://#{Webpacker.dev_server.host_with_port}" }
+  data_hosts.uniq!
 
-    p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url, *webpacker_urls
-    p.script_src  :self, :unsafe_inline, :unsafe_eval, assets_host
-    p.child_src   :self, :blob, assets_host
-    p.worker_src  :self, :blob, assets_host
-  else
-    p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url
-    p.script_src  :self, assets_host
-    p.child_src   :self, :blob, assets_host
-    p.worker_src  :self, :blob, assets_host
+  Rails.application.config.content_security_policy do |p|
+    p.base_uri        :none
+    p.default_src     :none
+    p.frame_ancestors :none
+    p.script_src      :self, assets_host
+    p.font_src        :self, assets_host
+    p.img_src         :self, :data, :blob, *data_hosts, "pool.jortage.com", "blob.jortage.com", "s3-us-east-2.amazonaws.com"
+    p.style_src       :self, assets_host
+    p.media_src       :self, :data, *data_hosts, "pool.jortage.com", "blob.jortage.com", "s3-us-east-2.amazonaws.com"
+    p.frame_src       :self, :https
+    p.child_src       :self, :blob, assets_host
+    p.worker_src      :self, :blob, assets_host
+    p.connect_src     :self, :blob, :data, Rails.configuration.x.streaming_api_base_url, *data_hosts
+    p.manifest_src    :self, assets_host
   end
 end
 
diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb
index 55f8c9c91..bc782bc76 100644
--- a/config/initializers/cors.rb
+++ b/config/initializers/cors.rb
@@ -30,5 +30,9 @@ Rails.application.config.middleware.insert_before 0, Rack::Cors do
       headers: :any,
       methods: [:post],
       credentials: false
+    resource '/assets/*', headers: :any, methods: [:get, :head, :options]
+    resource '/stylesheets/*', headers: :any, methods: [:get, :head, :options]
+    resource '/javascripts/*', headers: :any, methods: [:get, :head, :options]
+    resource '/packs/*', headers: :any, methods: [:get, :head, :options]
   end
 end
diff --git a/config/initializers/locale.rb b/config/initializers/locale.rb
new file mode 100644
index 000000000..fed182a71
--- /dev/null
+++ b/config/initializers/locale.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+I18n.load_path += Dir[Rails.root.join('app', 'javascript', 'flavours', '*', 'names.{rb,yml}').to_s]
+I18n.load_path += Dir[Rails.root.join('app', 'javascript', 'flavours', '*', 'names', '*.{rb,yml}').to_s]
+I18n.load_path += Dir[Rails.root.join('app', 'javascript', 'skins', '*', '*', 'names.{rb,yml}').to_s]
+I18n.load_path += Dir[Rails.root.join('app', 'javascript', 'skins', '*', '*', 'names', '*.{rb,yml}').to_s]
+I18n.load_path += Dir[Rails.root.join('config', 'locales-glitch', '*.{rb,yml}').to_s]
diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb
index 3dc48ef08..dcf6296fa 100644
--- a/config/initializers/simple_form.rb
+++ b/config/initializers/simple_form.rb
@@ -8,16 +8,7 @@ module AppendComponent
   end
 end
 
-module RecommendedComponent
-  def recommended(wrapper_options = nil)
-    return unless options[:recommended]
-    options[:label_text] = ->(raw_label_text, _required_label_text, _label_present) { safe_join([raw_label_text, ' ', content_tag(:span, I18n.t('simple_form.recommended'), class: 'recommended')]) }
-    nil
-  end
-end
-
 SimpleForm.include_component(AppendComponent)
-SimpleForm.include_component(RecommendedComponent)
 
 SimpleForm.setup do |config|
   # Wrappers are used by the form builder to generate a
@@ -74,7 +65,6 @@ SimpleForm.setup do |config|
     b.use :html5
 
     b.wrapper tag: :div, class: :label_input do |ba|
-      ba.optional :recommended
       ba.use :label
 
       ba.wrapper tag: :div, class: :label_input__wrapper do |bb|
diff --git a/config/locales-glitch/en.yml b/config/locales-glitch/en.yml
new file mode 100644
index 000000000..6268727a7
--- /dev/null
+++ b/config/locales-glitch/en.yml
@@ -0,0 +1,25 @@
+---
+en:
+  admin:
+    dashboard:
+      keybase: Keybase integration
+    settings:
+      enable_keybase:
+        desc_html: Allow your users to prove their identity via keybase
+        title: Enable keybase integration
+      outgoing_spoilers:
+        desc_html: When federating toots, add this content warning to toots that do not have one. It is useful if your server is specialized in content other servers might want to have under a Content Warning. Media will also be marked as sensitive.
+        title: Content warning for outgoing toots
+      hide_followers_count:
+        desc_html: Do not show followers count on user profiles
+        title: Hide followers count
+      show_reblogs_in_public_timelines:
+        desc_html: Show public boosts of public toots in local and public timelines.
+        title: Show boosts in public timelines
+      show_replies_in_public_timelines:
+        desc_html: In addition to public self-replies (threads), show public replies in local and public timelines.
+        title: Show replies in public timelines
+  generic:
+    use_this: Use this
+  settings:
+    flavours: Flavours
diff --git a/config/locales-glitch/es.yml b/config/locales-glitch/es.yml
new file mode 100644
index 000000000..7e8de1560
--- /dev/null
+++ b/config/locales-glitch/es.yml
@@ -0,0 +1,25 @@
+---
+es:
+  admin:
+    dashboard:
+      keybase: Integración con keybase
+    settings:
+      enable_keybase:
+        desc_html: Permite a tus usuarixs comprobar su identidad por medio de keybase
+        title: Habilitar la integración con keybase
+      outgoing_spoilers:
+        desc_html: Cuando los toots federen, agrega esta etiqueta de contenido a los toots que no tengan. Es útil si tu servidor se especializa en contenido que otros servidores desearían tener con una advertencia de contenido. Los medios también se marcarán como sensibles.
+        title: Advertencia de contenido para los toots salientes
+      hide_followers_count:
+        desc_html: No mostrar el conteo de seguidorxs en perfiles de usuarix
+        title: Ocultar conteo de seguidorxs
+      show_reblogs_in_public_timelines:
+        desc_html: Mostrar retoots públicos en las línea de tiempo local y pública.
+        title: Mostrar retoots en líneas de tiempo públicas
+      show_replies_in_public_timelines:
+        desc_html: Además de auto-respuestas públicas (hilos), mostrar respuestas públicas en las línea de tiempo local y pública.
+        title: Mostrar respuestas en líneas de tiempo públicas
+  generic:
+    use_this: Usar
+  settings:
+    flavours: Ediciones
\ No newline at end of file
diff --git a/config/locales-glitch/ja.yml b/config/locales-glitch/ja.yml
new file mode 100644
index 000000000..15fb6e566
--- /dev/null
+++ b/config/locales-glitch/ja.yml
@@ -0,0 +1,6 @@
+---
+ja:
+  generic:
+    use_this: これを使う
+  settings:
+    flavours: フレーバー
diff --git a/config/locales-glitch/pl.yml b/config/locales-glitch/pl.yml
new file mode 100644
index 000000000..3fcdedcf3
--- /dev/null
+++ b/config/locales-glitch/pl.yml
@@ -0,0 +1,6 @@
+---
+pl:
+  generic:
+    use_this: Użyj tego
+  settings:
+    flavours: Odmiany
diff --git a/config/locales-glitch/simple_form.en.yml b/config/locales-glitch/simple_form.en.yml
new file mode 100644
index 000000000..612943571
--- /dev/null
+++ b/config/locales-glitch/simple_form.en.yml
@@ -0,0 +1,20 @@
+---
+en:
+  simple_form:
+    hints:
+      defaults:
+        setting_default_content_type_html: When writing toots, assume they are written in raw HTML, unless specified otherwise
+        setting_default_content_type_markdown: When writing toots, assume they are using Markdown for rich text formatting, unless specified otherwise
+        setting_default_content_type_plain: When writing toots, assume they are plain text with no special formatting, unless specified otherwise (default Mastodon behavior)
+        setting_default_language: The language of your toots can be detected automatically, but it's not always accurate
+        setting_skin: Reskins the selected Mastodon flavour
+    labels:
+      defaults:
+        setting_default_content_type: Default format for toots
+        setting_default_content_type_html: HTML
+        setting_default_content_type_markdown: Markdown
+        setting_default_content_type_plain: Plain text
+        setting_favourite_modal: Show confirmation dialog before favouriting (applies to Glitch flavour only)
+        setting_hide_followers_count: Hide your followers count
+        setting_skin: Skin
+        setting_system_emoji_font: Use system's default font for emojis (applies to Glitch flavour only)
diff --git a/config/locales-glitch/simple_form.es.yml b/config/locales-glitch/simple_form.es.yml
new file mode 100644
index 000000000..977775be6
--- /dev/null
+++ b/config/locales-glitch/simple_form.es.yml
@@ -0,0 +1,20 @@
+---
+es:
+  simple_form:
+    hints:
+      defaults:
+        setting_default_content_type_html: Al escribir toots, asume que estás escritos en HTML, a menos que se especifique lo contrario
+        setting_default_content_type_markdown: Al escribir toots, asume que estás usando Markdown para dar formato de texto enriquecido, a menos que se especifique lo contrario
+        setting_default_content_type_plain: Al escribir toots, asume que estás usando texto sin formato, a menos que se especifique lo contrario (predeterminado de Mastodon)
+        setting_default_language: El idioma de tus toots se puede detectar automáticamente, pero no siempre es correcto
+        setting_skin: Cambia el diseño de la edición seleccionada de Mastodon
+    labels:
+      defaults:
+        setting_default_content_type: Formato predeterminado de tus toots
+        setting_default_content_type_html: HTML
+        setting_default_content_type_markdown: Markdown
+        setting_default_content_type_plain: Sin formato
+        setting_favourite_modal: Mostrar diálogo de confirmación antes de marcar como favorito (sólo aplica a la edición Glich)
+        setting_hide_followers_count: Ocultar tu conteo de seguidorxs
+        setting_skin: Diseño
+        setting_system_emoji_font: Usar la fuente predeterminada del sistema para emojis (sólo aplica a la edición Glitch)
diff --git a/config/locales-glitch/simple_form.ja.yml b/config/locales-glitch/simple_form.ja.yml
new file mode 100644
index 000000000..ba02c8091
--- /dev/null
+++ b/config/locales-glitch/simple_form.ja.yml
@@ -0,0 +1,6 @@
+---
+ja:
+  simple_form:
+    labels:
+      defaults:
+        setting_favourite_modal: お気に入りをする前に確認ダイアログを表示する
diff --git a/config/locales-glitch/simple_form.pl.yml b/config/locales-glitch/simple_form.pl.yml
new file mode 100644
index 000000000..264494c2d
--- /dev/null
+++ b/config/locales-glitch/simple_form.pl.yml
@@ -0,0 +1,10 @@
+---
+pl:
+  simple_form:
+    hints:
+      defaults:
+        setting_skin: Zmienia wygląd używanej odmiany Mastodona
+    labels:
+      defaults:
+        setting_favourite_modal: Pytaj o potwierdzenie przed dodaniem do ulubionych
+        setting_skin: Motyw
diff --git a/config/locales/en-cafe.yml b/config/locales/en-cafe.yml
new file mode 100755
index 000000000..b91edcf1d
--- /dev/null
+++ b/config/locales/en-cafe.yml
@@ -0,0 +1,18 @@
+---
+en-cafe:
+  about:
+    hosted_on: GlitchCafé hosted on %{domain}
+    unavailable_content: Domain blocks
+    unavailable_content_description:
+      domain: Instance
+      reason: Reason
+      rejecting_media: 'Media files from these instances will not be processed or stored, and no thumbnails will be displayed, requiring manual click-through to the original file:'
+      rejecting_media_title: Filtered media
+      silenced: 'Posts from these instances will be hidden in public timelines and conversations, and no notifications will be generated from their users interactions, unless you are following them:'
+      silenced_title: Silenced instances
+      suspended: 'No data from these instances will be processed, stored or exchanged, making any interaction or communication with users from these instances impossible:'
+      suspended_title: Suspended instances
+  auth:
+    description:
+      prefix_invited_by_user: "@%{name} invites you to join Plural Café!"
+      prefix_sign_up: Sign up on Plural Café today!
diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml
index 63f122b78..0663c65b4 100644
--- a/config/locales/simple_form.ar.yml
+++ b/config/locales/simple_form.ar.yml
@@ -180,7 +180,6 @@ ar:
         trendable: السماح لهذه الكلمة المفتاحية بالظهور تحت المتداوَلة
         usable: اسمح للتبويقات باستخدام هذا الوسم
     'no': لا
-    recommended: موصى بها
     required:
       mark: "*"
       text: مطلوب
diff --git a/config/locales/simple_form.ast.yml b/config/locales/simple_form.ast.yml
index 1a62eb76b..1fe5fa798 100644
--- a/config/locales/simple_form.ast.yml
+++ b/config/locales/simple_form.ast.yml
@@ -94,7 +94,6 @@ ast:
       tag:
         name: Etiqueta
     'no': Non
-    recommended: Aconséyase
     required:
       mark: "*"
       text: ríquese
diff --git a/config/locales/simple_form.ca.yml b/config/locales/simple_form.ca.yml
index b4d356279..2cf27f932 100644
--- a/config/locales/simple_form.ca.yml
+++ b/config/locales/simple_form.ca.yml
@@ -202,7 +202,6 @@ ca:
         trendable: Permet que aquesta etiqueta aparegui en les tendències
         usable: Permet als tuts emprar aquesta etiqueta
     'no': 'No'
-    recommended: Recomanat
     required:
       mark: "*"
       text: necessari
diff --git a/config/locales/simple_form.co.yml b/config/locales/simple_form.co.yml
index 508ecbc5f..cb5bbb8ec 100644
--- a/config/locales/simple_form.co.yml
+++ b/config/locales/simple_form.co.yml
@@ -202,7 +202,6 @@ co:
         trendable: Auturizà stu hashtag à esse vistu in e tendenze
         usable: Auturizà i statuti à utilizà stu hashtag
     'no': Nò
-    recommended: Ricumandati
     required:
       mark: "*"
       text: riquisiti
diff --git a/config/locales/simple_form.cs.yml b/config/locales/simple_form.cs.yml
index d03636247..9f3f36b1e 100644
--- a/config/locales/simple_form.cs.yml
+++ b/config/locales/simple_form.cs.yml
@@ -184,7 +184,6 @@ cs:
         trendable: Povolit tento hashtag v trendech
         usable: Povolit používat tento hashtag v tootech
     'no': Ne
-    recommended: Doporučeno
     required:
       mark: "*"
       text: vyžadováno
diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml
index cb3f75c1a..1b4250c0c 100644
--- a/config/locales/simple_form.cy.yml
+++ b/config/locales/simple_form.cy.yml
@@ -184,7 +184,6 @@ cy:
         trendable: Gadewch i'r hashnod hwn ymddangos o dan dueddiadau
         usable: Caniatáu i tŵtiau ddefnyddio'r hashnod hwn
     'no': Na
-    recommended: Argymhellwyd
     required:
       mark: "*"
       text: gofynnol
diff --git a/config/locales/simple_form.da.yml b/config/locales/simple_form.da.yml
index 1c16c8e37..fb011f573 100644
--- a/config/locales/simple_form.da.yml
+++ b/config/locales/simple_form.da.yml
@@ -156,7 +156,6 @@ da:
         trendable: Tillad at dette hashtag vises under trends
         usable: Tillad toots at benytte dette hashtag
     'no': Nej
-    recommended: Anbefalet
     required:
       mark: "*"
       text: påkrævet
diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml
index 72303a375..8fa7ccff8 100644
--- a/config/locales/simple_form.de.yml
+++ b/config/locales/simple_form.de.yml
@@ -202,7 +202,6 @@ de:
         trendable: Erlaube es diesen Hashtag in den Trends erscheinen zu lassen
         usable: Beiträge erlauben, diesen Hashtag zu verwenden
     'no': Nein
-    recommended: Empfohlen
     required:
       mark: "*"
       text: Pflichtfeld
diff --git a/config/locales/simple_form.el.yml b/config/locales/simple_form.el.yml
index aaa0d7ae0..503adafd2 100644
--- a/config/locales/simple_form.el.yml
+++ b/config/locales/simple_form.el.yml
@@ -189,7 +189,6 @@ el:
         trendable: Εμφάνιση της ετικέτας στις τάσεις
         usable: Χρήση της ετικέτας σε τουτ
     'no': Όχι
-    recommended: Προτείνεται
     required:
       mark: "*"
       text: απαιτείται
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 46a4759a8..f982d50f9 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -64,7 +64,7 @@ en:
       imports:
         data: CSV file exported from another Mastodon server
       invite_request:
-        text: This will help us review your application
+        text: 'If you are interested in signing up, please put whether you are a plural system or singlet in the "Why do you want to join" box. This is purely to ward off spam bots. If this is not answered, your request to join the instance will be rejected.'
       ip_block:
         comment: Optional. Remember why you added this rule.
         expires_in: IP addresses are a finite resource, they are sometimes shared and often change hands. For this reason, indefinite IP blocks are not recommended.
@@ -202,7 +202,6 @@ en:
         trendable: Allow this hashtag to appear under trends
         usable: Allow toots to use this hashtag
     'no': 'No'
-    recommended: Recommended
     required:
       mark: "*"
       text: required
diff --git a/config/locales/simple_form.eo.yml b/config/locales/simple_form.eo.yml
index 98fda0916..52b5409c8 100644
--- a/config/locales/simple_form.eo.yml
+++ b/config/locales/simple_form.eo.yml
@@ -160,7 +160,6 @@ eo:
         trendable: Permesi al ĉi tiu kradvorto aperi en furoraĵoj
         usable: Permesi mesaĝojn uzi ĉi tiun kradvorton
     'no': Ne
-    recommended: Rekomendita
     required:
       mark: "*"
       text: bezonata
diff --git a/config/locales/simple_form.es-AR.yml b/config/locales/simple_form.es-AR.yml
index cc27b9643..b109b69a8 100644
--- a/config/locales/simple_form.es-AR.yml
+++ b/config/locales/simple_form.es-AR.yml
@@ -202,7 +202,6 @@ es-AR:
         trendable: Permitir que esta etiqueta aparezca bajo tendencias
         usable: Permitir a los toots usar esta etiqueta
     'no': 'No'
-    recommended: Opción recomendada
     required:
       mark: "*"
       text: obligatorio
diff --git a/config/locales/simple_form.es.yml b/config/locales/simple_form.es.yml
index f53bdd143..853c572d5 100644
--- a/config/locales/simple_form.es.yml
+++ b/config/locales/simple_form.es.yml
@@ -202,7 +202,6 @@ es:
         trendable: Permitir que esta etiqueta aparezca bajo tendencias
         usable: Permitir a los toots usar esta etiqueta
     'no': 'No'
-    recommended: Recomendado
     required:
       mark: "*"
       text: necesario
diff --git a/config/locales/simple_form.et.yml b/config/locales/simple_form.et.yml
index 79934c0b1..93154745d 100644
--- a/config/locales/simple_form.et.yml
+++ b/config/locales/simple_form.et.yml
@@ -183,7 +183,6 @@ et:
         trendable: Luba sellel sildil trendida
         usable: Luba tuututustel seda silti kasutada
     'no': Ei
-    recommended: Soovituslik
     required:
       mark: "*"
       text: kohustuslik
diff --git a/config/locales/simple_form.eu.yml b/config/locales/simple_form.eu.yml
index c3520b072..41eded347 100644
--- a/config/locales/simple_form.eu.yml
+++ b/config/locales/simple_form.eu.yml
@@ -183,7 +183,6 @@ eu:
         trendable: Baimendu traola hau joeretan agertzea
         usable: Baimendu tootek traola hau erabiltzea
     'no': Ez
-    recommended: Aholkatua
     required:
       mark: "*"
       text: beharrezkoa
diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml
index 6425011b6..fff056eab 100644
--- a/config/locales/simple_form.fa.yml
+++ b/config/locales/simple_form.fa.yml
@@ -202,7 +202,6 @@ fa:
         trendable: بگذارید که این برچسب در موضوعات پرطرفدار دیده شود
         usable: بگذارید که این برچسب در بوق‌ها به کار بروند
     'no': خیر
-    recommended: توصیه می‌شود
     required:
       mark: "*"
       text: ضروری
diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml
index 1b4acc9b9..74eda70fc 100644
--- a/config/locales/simple_form.fi.yml
+++ b/config/locales/simple_form.fi.yml
@@ -128,7 +128,6 @@ fi:
         trendable: Salli tämän aihetunnisteen näkyä trendeissä
         usable: Salli tuuttauksien käyttää tätä aihetunnistetta
     'no': Ei
-    recommended: Suositeltu
     required:
       mark: "*"
       text: pakollinen tieto
diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml
index 51446f63c..42673a640 100644
--- a/config/locales/simple_form.fr.yml
+++ b/config/locales/simple_form.fr.yml
@@ -202,7 +202,6 @@ fr:
         trendable: Autoriser ce hashtag à apparaitre dans les tendances
         usable: Autoriser les pouets à utiliser ce hashtag
     'no': Non
-    recommended: Recommandé
     required:
       mark: "*"
       text: champs requis
diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml
index f2ebf1d6e..5a277e665 100644
--- a/config/locales/simple_form.gl.yml
+++ b/config/locales/simple_form.gl.yml
@@ -202,7 +202,6 @@ gl:
         trendable: Permitir que este cancelo apareza en tendencias
         usable: Permitir que os toots utilicen este cancelo
     'no': Non
-    recommended: Recomendado
     required:
       mark: "*"
       text: requerido
diff --git a/config/locales/simple_form.hu.yml b/config/locales/simple_form.hu.yml
index 242f1ffac..388aacca0 100644
--- a/config/locales/simple_form.hu.yml
+++ b/config/locales/simple_form.hu.yml
@@ -202,7 +202,6 @@ hu:
         trendable: A hashtag megjelenhet a trendek között
         usable: Tülkök használhatják ezt a hashtaget
     'no': Nem
-    recommended: Ajánlott
     required:
       mark: "*"
       text: kötelező
diff --git a/config/locales/simple_form.hy.yml b/config/locales/simple_form.hy.yml
index aaa5d88e5..2b1033308 100644
--- a/config/locales/simple_form.hy.yml
+++ b/config/locales/simple_form.hy.yml
@@ -193,7 +193,6 @@ hy:
         trendable: Թոյլատրել, որ այս պիտակը յայտնուի թրենդներում
         usable: Թոյլատրել թթերին օգտագործել այս պիտակը
     'no': Ոչ
-    recommended: Խորհուրդ է տրվում
     required:
       mark: "*"
       text: պարտադիր
diff --git a/config/locales/simple_form.id.yml b/config/locales/simple_form.id.yml
index c94a5377a..c15907f05 100644
--- a/config/locales/simple_form.id.yml
+++ b/config/locales/simple_form.id.yml
@@ -202,7 +202,6 @@ id:
         trendable: Izinkan tagar ini muncul di bawah tren
         usable: Izinkan toot memakai tagar ini
     'no': Tidak
-    recommended: Direkomendasikan
     required:
       mark: "*"
       text: wajib
diff --git a/config/locales/simple_form.is.yml b/config/locales/simple_form.is.yml
index ed948a699..4c1f0ce93 100644
--- a/config/locales/simple_form.is.yml
+++ b/config/locales/simple_form.is.yml
@@ -202,7 +202,6 @@ is:
         trendable: Leyfa þessu myllumerki að birtast undir tilhneigingum
         usable: Leyfa tístum að nota þetta myllumerki
     'no': Nei
-    recommended: Mælt með
     required:
       mark: "*"
       text: nauðsynlegt
diff --git a/config/locales/simple_form.it.yml b/config/locales/simple_form.it.yml
index 1e79d593d..a0c3f0057 100644
--- a/config/locales/simple_form.it.yml
+++ b/config/locales/simple_form.it.yml
@@ -202,7 +202,6 @@ it:
         trendable: Permetti a questo hashtag di apparire nelle tendenze
         usable: Permetti ai toot di utilizzare questo hashtag
     'no': 'No'
-    recommended: Consigliato
     required:
       mark: "*"
       text: richiesto
diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml
index 36ee01a1f..7b3b0bb3d 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -202,7 +202,6 @@ ja:
         trendable: トレンドへの表示を許可する
         usable: トゥートへの使用を許可する
     'no': いいえ
-    recommended: おすすめ
     required:
       mark: "*"
       text: 必須
diff --git a/config/locales/simple_form.kab.yml b/config/locales/simple_form.kab.yml
index bbc23ed51..2e7f93a34 100644
--- a/config/locales/simple_form.kab.yml
+++ b/config/locales/simple_form.kab.yml
@@ -99,7 +99,6 @@ kab:
       tag:
         name: Ahacṭag
     'no': Ala
-    recommended: Yettuwelleh
     required:
       mark: "*"
       text: ilaq
diff --git a/config/locales/simple_form.kk.yml b/config/locales/simple_form.kk.yml
index 544c684a6..859c70418 100644
--- a/config/locales/simple_form.kk.yml
+++ b/config/locales/simple_form.kk.yml
@@ -164,7 +164,6 @@ kk:
         trendable: Хештегті трендтерде көрсетуге рұқсат бер
         usable: Бұл хештегті қолдануға рұқсат бер
     'no': Жоқ
-    recommended: Рекоменделген
     required:
       mark: "*"
       text: міндетті
diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml
index 8588073d8..b6b3b40a2 100644
--- a/config/locales/simple_form.ko.yml
+++ b/config/locales/simple_form.ko.yml
@@ -202,7 +202,6 @@ ko:
         trendable: 이 해시태그가 유행에 보여지도록 허용
         usable: 이 해시태그를 툿에 사용 가능하도록 허용
     'no': 아니오
-    recommended: 추천함
     required:
       mark: "*"
       text: 필수 항목
diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml
index 7989f6981..454180007 100644
--- a/config/locales/simple_form.nl.yml
+++ b/config/locales/simple_form.nl.yml
@@ -184,7 +184,6 @@ nl:
         trendable: Toestaan dat deze hashtag onder trends te zien valt
         usable: Toestaan dat deze hashtag in toots gebruikt mag worden
     'no': Nee
-    recommended: Aanbevolen
     required:
       mark: "*"
       text: vereist
diff --git a/config/locales/simple_form.nn.yml b/config/locales/simple_form.nn.yml
index f4a62ac07..a28bcaef8 100644
--- a/config/locales/simple_form.nn.yml
+++ b/config/locales/simple_form.nn.yml
@@ -195,7 +195,6 @@ nn:
         trendable: Tillat denne emneknaggen til å synast under trendar
         usable: Gje tut lov til å nytta denne emneknaggen
     'no': Nei
-    recommended: Tilrådt
     required:
       mark: "*"
       text: obligatorisk
diff --git a/config/locales/simple_form.no.yml b/config/locales/simple_form.no.yml
index cdf3d61e8..65eb6fba8 100644
--- a/config/locales/simple_form.no.yml
+++ b/config/locales/simple_form.no.yml
@@ -195,7 +195,6 @@
         trendable: Tillat denne emneknaggen til å vises under trender
         usable: Tillat tuter å bruke denne emneknaggen
     'no': Nei
-    recommended: Anbefalt
     required:
       mark: "*"
       text: obligatorisk
diff --git a/config/locales/simple_form.oc.yml b/config/locales/simple_form.oc.yml
index 120ddfbe0..b6e6ee66f 100644
--- a/config/locales/simple_form.oc.yml
+++ b/config/locales/simple_form.oc.yml
@@ -202,7 +202,6 @@ oc:
         trendable: Permetre a aquesta etiqueta d’aparéisser a las tendéncias
         usable: Permetre als tuts d’utilizar aquesta etiqueta
     'no': Non
-    recommended: Recomandat
     required:
       mark: "*"
       text: requesit
diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml
index a02d0be35..4f71f974c 100644
--- a/config/locales/simple_form.pl.yml
+++ b/config/locales/simple_form.pl.yml
@@ -202,7 +202,6 @@ pl:
         trendable: Pozwól na wyświetlanie tego hashtagu w „Na czasie”
         usable: Pozwól na umieszczanie tego hashtagu we wpisach
     'no': Nie
-    recommended: Polecane
     required:
       mark: "*"
       text: pole wymagane
diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml
index ea53a3c83..c4819484f 100644
--- a/config/locales/simple_form.pt-BR.yml
+++ b/config/locales/simple_form.pt-BR.yml
@@ -202,7 +202,6 @@ pt-BR:
         trendable: Permitir que esta hashtag fique em alta
         usable: Permitir que toots usem esta hashtag
     'no': Não
-    recommended: Recomendado
     required:
       mark: "*"
       text: obrigatório
diff --git a/config/locales/simple_form.pt-PT.yml b/config/locales/simple_form.pt-PT.yml
index 614d78c55..3c0bf994b 100644
--- a/config/locales/simple_form.pt-PT.yml
+++ b/config/locales/simple_form.pt-PT.yml
@@ -202,7 +202,6 @@ pt-PT:
         trendable: Permitir que esta hashtag apareça em destaque
         usable: Permitir que toots utilizem esta hashtag
     'no': Não
-    recommended: Recomendado
     required:
       mark: "*"
       text: obrigatório
diff --git a/config/locales/simple_form.ro.yml b/config/locales/simple_form.ro.yml
index aa0b07708..36ac81b65 100644
--- a/config/locales/simple_form.ro.yml
+++ b/config/locales/simple_form.ro.yml
@@ -183,7 +183,6 @@ ro:
         trendable: Permite acestui hashtag să apară sub tendințe
         usable: Permite postărilor să folosească acest hashtag
     'no': Nu
-    recommended: Recomandat
     required:
       mark: "*"
       text: obligatoriu
diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml
index fdd60c881..40003b1ac 100644
--- a/config/locales/simple_form.ru.yml
+++ b/config/locales/simple_form.ru.yml
@@ -202,7 +202,6 @@ ru:
         trendable: Разрешить показ хэштега в трендах
         usable: Разрешить использовать этот хэштег в постах
     'no': Нет
-    recommended: Рекомендуем
     required:
       mark: "*"
       text: обязательно
diff --git a/config/locales/simple_form.sk.yml b/config/locales/simple_form.sk.yml
index 9e03d7254..a5fdc2a69 100644
--- a/config/locales/simple_form.sk.yml
+++ b/config/locales/simple_form.sk.yml
@@ -170,7 +170,6 @@ sk:
         trendable: Povoľ zobrazovanie tohto haštagu medzi trendujúcimi
         usable: Povoľ používanie tohto haštagu v príspevkoch
     'no': Nie
-    recommended: Odporúčané
     required:
       mark: "*"
       text: povinné
diff --git a/config/locales/simple_form.sl.yml b/config/locales/simple_form.sl.yml
index 771edf383..31648b119 100644
--- a/config/locales/simple_form.sl.yml
+++ b/config/locales/simple_form.sl.yml
@@ -137,7 +137,6 @@ sl:
         reblog: Pošlji e-pošto, ko nekdo sune vaše stanje
         report: Pošlji e-pošto, ko je oddana nova prijava
     'no': Ne
-    recommended: Priporočeno
     required:
       mark: "*"
       text: zahtevano
diff --git a/config/locales/simple_form.sq.yml b/config/locales/simple_form.sq.yml
index ac95ab570..1b2a2e7fd 100644
--- a/config/locales/simple_form.sq.yml
+++ b/config/locales/simple_form.sq.yml
@@ -202,7 +202,6 @@ sq:
         trendable: Lejoje këtë hashtag të shfaqet në prirje
         usable: Lejoji mesazhet të përdorin këtë hashtag
     'no': Jo
-    recommended: E rekomanduar
     required:
       mark: "*"
       text: e domosdoshme
diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml
index dd7769fca..7c7eae49c 100644
--- a/config/locales/simple_form.sv.yml
+++ b/config/locales/simple_form.sv.yml
@@ -120,7 +120,6 @@ sv:
         mention: Skicka e-post när någon nämner dig
         reblog: Skicka e-post när någon knuffar din status
     'no': Nej
-    recommended: Rekommenderad
     required:
       mark: "*"
       text: obligatorisk
diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml
index 7d2116740..514500e49 100644
--- a/config/locales/simple_form.th.yml
+++ b/config/locales/simple_form.th.yml
@@ -193,7 +193,6 @@ th:
         trendable: อนุญาตให้แฮชแท็กนี้ปรากฏภายใต้แนวโน้ม
         usable: อนุญาตให้โพสต์ใช้แฮชแท็กนี้
     'no': ไม่
-    recommended: แนะนำ
     required:
       mark: "*"
       text: ต้องระบุ
diff --git a/config/locales/simple_form.tr.yml b/config/locales/simple_form.tr.yml
index 04b0f26a3..8653085c4 100644
--- a/config/locales/simple_form.tr.yml
+++ b/config/locales/simple_form.tr.yml
@@ -202,7 +202,6 @@ tr:
         trendable: Bu etiketin gündem altında görünmesine izin ver
         usable: Tootların bu etiketi kullanmasına izin ver
     'no': Hayır
-    recommended: Önerilen
     required:
       mark: "*"
       text: gerekli
diff --git a/config/locales/simple_form.uk.yml b/config/locales/simple_form.uk.yml
index adfc07a09..7580ef0c1 100644
--- a/config/locales/simple_form.uk.yml
+++ b/config/locales/simple_form.uk.yml
@@ -185,7 +185,6 @@ uk:
         trendable: Дозволити появу цього хештеґа у списку популярних хештеґів
         usable: Дозволити дмухам використовувати цей хештеґ
     'no': Ні
-    recommended: Рекомендовано
     required:
       mark: "*"
       text: обов'язкове
diff --git a/config/locales/simple_form.vi.yml b/config/locales/simple_form.vi.yml
index 99611febf..98154ce58 100644
--- a/config/locales/simple_form.vi.yml
+++ b/config/locales/simple_form.vi.yml
@@ -202,7 +202,6 @@ vi:
         trendable: Cho phép hashtag này xuất hiện trong xu hướng
         usable: Cho phép dùng hashtag này trong tút
     'no': Tắt
-    recommended: Khuyến nghị
     required:
       mark: "*"
       text: yêu cầu
diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml
index 6d2eb2f49..76c97ffd5 100644
--- a/config/locales/simple_form.zh-CN.yml
+++ b/config/locales/simple_form.zh-CN.yml
@@ -202,7 +202,6 @@ zh-CN:
         trendable: 允许在热门下显示此话题
         usable: 允许嘟文使用此话题标签
     'no': 否
-    recommended: 推荐
     required:
       mark: "*"
       text: 必填
diff --git a/config/locales/simple_form.zh-HK.yml b/config/locales/simple_form.zh-HK.yml
index 843157815..57b20fd4a 100644
--- a/config/locales/simple_form.zh-HK.yml
+++ b/config/locales/simple_form.zh-HK.yml
@@ -186,7 +186,6 @@ zh-HK:
         trendable: 允許此主題標籤在趨勢下顯示
         usable: 允許嘟文使用此主題標籤
     'no': 否
-    recommended: 建議
     required:
       mark: "*"
       text: 必須填寫
diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml
index 80cc8c2ee..a563443d7 100644
--- a/config/locales/simple_form.zh-TW.yml
+++ b/config/locales/simple_form.zh-TW.yml
@@ -162,7 +162,6 @@ zh-TW:
         trendable: 允許此主題標籤在趨勢下顯示
         usable: 允許嘟文使用此主題標籤
     'no': 否
-    recommended: 建議
     required:
       mark: "*"
       text: 必須填寫
diff --git a/config/navigation.rb b/config/navigation.rb
index 4a56abe18..be429cfc4 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -16,6 +16,12 @@ SimpleNavigation::Configuration.run do |navigation|
       s.item :other, safe_join([fa_icon('cog fw'), t('preferences.other')]), settings_preferences_other_url
     end
 
+    n.item :flavours, safe_join([fa_icon('paint-brush fw'), t('settings.flavours')]), settings_flavours_url do |flavours|
+      Themes.instance.flavours.each do |flavour|
+        flavours.item flavour.to_sym, safe_join([fa_icon('star fw'), t("flavours.#{flavour}.name", default: flavour)]), settings_flavour_url(flavour)
+      end
+    end
+
     n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_url, if: -> { current_user.functional? }
     n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? }
 
diff --git a/config/routes.rb b/config/routes.rb
index a534b433e..b3eef3364 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -158,6 +158,8 @@ Rails.application.routes.draw do
       end
     end
 
+    resources :flavours, only: [:index, :show, :update], param: :flavour
+
     resource :delete, only: [:show, :destroy]
     resource :migration, only: [:show, :create]
 
@@ -340,6 +342,7 @@ Rails.application.routes.draw do
       end
 
       namespace :timelines do
+        resource :direct, only: :show, controller: :direct
         resource :home, only: :show, controller: :home
         resource :public, only: :show, controller: :public
         resources :tag, only: :show
@@ -417,9 +420,10 @@ Rails.application.routes.draw do
         end
       end
 
-      resources :notifications, only: [:index, :show] do
+      resources :notifications, only: [:index, :show, :destroy] do
         collection do
           post :clear
+          delete :destroy_multiple
         end
 
         member do
diff --git a/config/settings.yml b/config/settings.yml
index 217745f28..4d6a1cffc 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -2,7 +2,7 @@
 # important settings can be changed from the admin interface.
 
 defaults: &defaults
-  site_title: Mastodon
+  site_title: 'dev.glitch.social'
   site_short_description: ''
   site_description: ''
   site_extended_description: ''
@@ -13,13 +13,14 @@ defaults: &defaults
   profile_directory: true
   closed_registrations_message: ''
   open_deletion: true
+  timeline_preview: false
   min_invite_role: 'admin'
-  timeline_preview: true
   show_staff_badge: true
   default_sensitive: false
   hide_network: false
   unfollow_modal: false
   boost_modal: false
+  favourite_modal: false
   delete_modal: true
   auto_play_gif: false
   display_media: 'default'
@@ -27,10 +28,14 @@ defaults: &defaults
   preview_sensitive_media: false
   reduce_motion: false
   disable_swiping: false
-  show_application: true
+  show_application: false
   system_font_ui: false
+  system_emoji_font: false
   noindex: false
-  theme: 'default'
+  hide_followers_count: false
+  enable_keybase: true
+  flavour: 'glitch'
+  skin: 'default'
   aggregate_reblogs: true
   advanced_layout: false
   use_blurhash: true
@@ -67,9 +72,13 @@ defaults: &defaults
   activity_api_enabled: true
   peers_api_enabled: true
   show_known_fediverse_at_about_page: true
+  show_reblogs_in_public_timelines: false
+  show_replies_in_public_timelines: false
+  default_content_type: 'text/plain'
   spam_check_enabled: true
   show_domain_blocks: 'disabled'
   show_domain_blocks_rationale: 'disabled'
+  outgoing_spoilers: ''
 
 development:
   <<: *defaults
diff --git a/config/themes.yml b/config/themes.yml
deleted file mode 100644
index 9c21c9459..000000000
--- a/config/themes.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-default: styles/application.scss
-contrast: styles/contrast.scss
-mastodon-light: styles/mastodon-light.scss
diff --git a/config/webpack/configuration.js b/config/webpack/configuration.js
index e4f88a9c4..b34ba0e0a 100644
--- a/config/webpack/configuration.js
+++ b/config/webpack/configuration.js
@@ -1,15 +1,61 @@
 // Common configuration for webpacker loaded from config/webpacker.yml
 
-const { resolve } = require('path');
+const { basename, dirname, extname, join, resolve } = require('path');
 const { env } = require('process');
 const { safeLoad } = require('js-yaml');
-const { readFileSync } = require('fs');
+const { lstatSync, readFileSync } = require('fs');
+const glob = require('glob');
 
 const configPath = resolve('config', 'webpacker.yml');
 const settings = safeLoad(readFileSync(configPath), 'utf8')[env.RAILS_ENV || env.NODE_ENV];
+const flavourFiles = glob.sync('app/javascript/flavours/*/theme.yml');
+const skinFiles = glob.sync('app/javascript/skins/*/*');
+const flavours = {};
 
-const themePath = resolve('config', 'themes.yml');
-const themes = safeLoad(readFileSync(themePath), 'utf8');
+const core = function () {
+  const coreFile = resolve('app', 'javascript', 'core', 'theme.yml');
+  const data = safeLoad(readFileSync(coreFile), 'utf8');
+  if (!data.pack_directory) {
+    data.pack_directory = dirname(coreFile);
+  }
+  return data.pack ? data : {};
+}();
+
+for (let i = 0; i < flavourFiles.length; i++) {
+  const flavourFile = flavourFiles[i];
+  const data = safeLoad(readFileSync(flavourFile), 'utf8');
+  data.name = basename(dirname(flavourFile));
+  data.skin = {};
+  if (!data.pack_directory) {
+    data.pack_directory = dirname(flavourFile);
+  }
+  if (data.locales) {
+    data.locales = join(dirname(flavourFile), data.locales);
+  }
+  if (data.pack && typeof data.pack === 'object') {
+    flavours[data.name] = data;
+  }
+}
+
+for (let i = 0; i < skinFiles.length; i++) {
+  const skinFile = skinFiles[i];
+  let skin = basename(skinFile);
+  const name = basename(dirname(skinFile));
+  if (!flavours[name]) {
+    continue;
+  }
+  const data = flavours[name].skin;
+  if (lstatSync(skinFile).isDirectory()) {
+    data[skin] = {};
+    const skinPacks = glob.sync(join(skinFile, '*.{css,scss}'));
+    for (let j = 0; j < skinPacks.length; j++) {
+      const pack = skinPacks[j];
+      data[skin][basename(pack, extname(pack))] = pack;
+    }
+  } else if ((skin = skin.match(/^(.*)\.s?css$/i))) {
+    data[skin[1]] = { common: skinFile };
+  }
+}
 
 const output = {
   path: resolve('public', settings.public_output_path),
@@ -18,7 +64,8 @@ const output = {
 
 module.exports = {
   settings,
-  themes,
+  core,
+  flavours,
   env: {
     NODE_ENV: env.NODE_ENV,
     PUBLIC_OUTPUT_PATH: settings.public_output_path,
diff --git a/config/webpack/generateLocalePacks.js b/config/webpack/generateLocalePacks.js
index b71cf2ade..09fba4a18 100644
--- a/config/webpack/generateLocalePacks.js
+++ b/config/webpack/generateLocalePacks.js
@@ -1,52 +1,66 @@
+// A message from upstream:
+// ========================
 // To avoid adding a lot of boilerplate, locale packs are
 // automatically generated here. These are written into the tmp/
 // directory and then used to generate locale_en.js, locale_fr.js, etc.
 
-const fs = require('fs');
-const path = require('path');
+// Glitch note:
+// ============
+// This code has been entirely rewritten to support glitch flavours.
+// However, the underlying process is exactly the same.
+
+const { existsSync, readdirSync, writeFileSync } = require('fs');
+const { join, resolve } = require('path');
 const rimraf = require('rimraf');
 const mkdirp = require('mkdirp');
+const { flavours } = require('./configuration.js');
+
+module.exports = Object.keys(flavours).reduce(function (map, entry) {
+  const flavour = flavours[entry];
+  if (!flavour.locales) {
+    return map;
+  }
+  const locales = readdirSync(flavour.locales).filter(
+    filename => /\.js(?:on)?$/.test(filename) && !/defaultMessages|whitelist|index/.test(filename)
+  );
+  const outPath = resolve('tmp', 'locales', entry);
 
-const localesJsonPath = path.join(__dirname, '../../app/javascript/mastodon/locales');
-const locales = fs.readdirSync(localesJsonPath).filter(filename => {
-  return /\.json$/.test(filename) &&
-    !/defaultMessages/.test(filename) &&
-    !/whitelist/.test(filename);
-}).map(filename => filename.replace(/\.json$/, ''));
-
-const outPath = path.join(__dirname, '../../tmp/packs');
-
-rimraf.sync(outPath);
-mkdirp.sync(outPath);
-
-const outPaths = [];
-
-locales.forEach(locale => {
-  const localePath = path.join(outPath, `locale_${locale}.js`);
-  const baseLocale = locale.split('-')[0]; // e.g. 'zh-TW' -> 'zh'
-  const localeDataPath = [
-    // first try react-intl
-    `../../node_modules/react-intl/locale-data/${baseLocale}.js`,
-    // then check locales/locale-data
-    `../../app/javascript/mastodon/locales/locale-data/${baseLocale}.js`,
-    // fall back to English (this is what react-intl does anyway)
-    '../../node_modules/react-intl/locale-data/en.js',
-  ].filter(filename => fs.existsSync(path.join(outPath, filename)))
-    .map(filename => filename.replace(/..\/..\/node_modules\//, ''))[0];
-
-  const localeContent = `//
-// locale_${locale}.js
+  rimraf.sync(outPath);
+  mkdirp.sync(outPath);
+
+  locales.forEach(function (locale) {
+    const localeName = locale.replace(/\.js(?:on)?$/, '');
+    const localePath = join(outPath, `${localeName}.js`);
+    const baseLocale = localeName.split('-')[0]; // e.g. 'zh-TW' -> 'zh'
+    const localeDataPath = [
+      // first try react-intl
+      `node_modules/react-intl/locale-data/${baseLocale}.js`,
+      // then check locales/locale-data
+      `app/javascript/locales/locale-data/${baseLocale}.js`,
+      // fall back to English (this is what react-intl does anyway)
+      'node_modules/react-intl/locale-data/en.js',
+    ].filter(
+      filename => existsSync(filename)
+    ).map(
+      filename => filename.replace(/(?:node_modules|app\/javascript)\//, '')
+    )[0];
+    const localeContent = `//
+// locales/${entry}/${localeName}.js
 // automatically generated by generateLocalePacks.js
 //
-import messages from '../../app/javascript/mastodon/locales/${locale}.json';
-import localeData from ${JSON.stringify(localeDataPath)};
-import { setLocale } from '../../app/javascript/mastodon/locales';
-setLocale({messages, localeData});
-`;
-  fs.writeFileSync(localePath, localeContent, 'utf8');
-  outPaths.push(localePath);
-});
 
-module.exports = outPaths;
+import messages from '../../../${flavour.locales}/${locale.replace(/\.js$/, '')}';
+import localeData from '${localeDataPath}';
+import { setLocale } from 'locales';
 
+setLocale({
+  localeData,
+  messages,
+});
+`;
+    writeFileSync(localePath, localeContent, 'utf8');
+    map[`locales/${entry}/${localeName}`] = localePath;
+  });
 
+  return map;
+}, {});
diff --git a/config/webpack/rules/babel.js b/config/webpack/rules/babel.js
index 2fc245c43..4d25748ee 100644
--- a/config/webpack/rules/babel.js
+++ b/config/webpack/rules/babel.js
@@ -12,6 +12,7 @@ module.exports = {
     {
       loader: 'babel-loader',
       options: {
+        sourceRoot: 'app/javascript',
         cacheDirectory: join(settings.cache_path, 'babel-loader'),
         cacheCompression: env.NODE_ENV === 'production',
         compact: env.NODE_ENV === 'production',
diff --git a/config/webpack/rules/css.js b/config/webpack/rules/css.js
index bc1f42c13..6ecfb3164 100644
--- a/config/webpack/rules/css.js
+++ b/config/webpack/rules/css.js
@@ -20,6 +20,9 @@ module.exports = {
     {
       loader: 'sass-loader',
       options: {
+        sassOptions: {
+          includePaths: ['app/javascript'],
+        },
         implementation: require('sass'),
         sourceMap: true,
       },
diff --git a/config/webpack/shared.js b/config/webpack/shared.js
index 05828aebe..ce08ac206 100644
--- a/config/webpack/shared.js
+++ b/config/webpack/shared.js
@@ -5,33 +5,56 @@ const { basename, dirname, join, relative, resolve } = require('path');
 const { sync } = require('glob');
 const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 const AssetsManifestPlugin = require('webpack-assets-manifest');
-const extname = require('path-complete-extname');
-const { env, settings, themes, output } = require('./configuration');
+const { env, settings, core, flavours, output } = require('./configuration.js');
 const rules = require('./rules');
-const localePackPaths = require('./generateLocalePacks');
+const localePacks = require('./generateLocalePacks');
+
+function reducePacks (data, into = {}) {
+  if (!data.pack) {
+    return into;
+  }
+  Object.keys(data.pack).reduce((map, entry) => {
+    const pack = data.pack[entry];
+    if (!pack) {
+      return map;
+    }
+    const packFile = typeof pack === 'string' ? pack : pack.filename;
+    if (packFile) {
+      map[data.name ? `flavours/${data.name}/${entry}` : `core/${entry}`] = resolve(data.pack_directory, packFile);
+    }
+    return map;
+  }, into);
+  if (data.name) {
+    Object.keys(data.skin).reduce((map, entry) => {
+      const skin = data.skin[entry];
+      const skinName = entry;
+      if (!skin) {
+        return map;
+      }
+      Object.keys(skin).reduce((map, entry) => {
+        const packFile = skin[entry];
+        if (!packFile) {
+          return map;
+        }
+        map[`skins/${data.name}/${skinName}/${entry}`] = resolve(packFile);
+        return map;
+      }, into);
+      return map;
+    }, into);
+  }
+  return into;
+}
+
+const entries = Object.assign(
+  { locales: resolve('app', 'javascript', 'locales') },
+  localePacks,
+  reducePacks(core),
+  Object.keys(flavours).reduce((map, entry) => reducePacks(flavours[entry], map), {})
+);
 
-const extensionGlob = `**/*{${settings.extensions.join(',')}}*`;
-const entryPath = join(settings.source_path, settings.source_entry_path);
-const packPaths = sync(join(entryPath, extensionGlob));
 
 module.exports = {
-  entry: Object.assign(
-    packPaths.reduce((map, entry) => {
-      const localMap = map;
-      const namespace = relative(join(entryPath), dirname(entry));
-      localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry);
-      return localMap;
-    }, {}),
-    localePackPaths.reduce((map, entry) => {
-      const localMap = map;
-      localMap[basename(entry, extname(entry, extname(entry)))] = resolve(entry);
-      return localMap;
-    }, {}),
-    Object.keys(themes).reduce((themePaths, name) => {
-      themePaths[name] = resolve(join(settings.source_path, themes[name]));
-      return themePaths;
-    }, {}),
-  ),
+  entry: entries,
 
   output: {
     filename: 'js/[name]-[chunkhash].js',
@@ -43,7 +66,7 @@ module.exports = {
 
   optimization: {
     runtimeChunk: {
-      name: 'common',
+      name: 'locales',
     },
     splitChunks: {
       cacheGroups: {
@@ -51,7 +74,9 @@ module.exports = {
         vendors: false,
         common: {
           name: 'common',
-          chunks: 'all',
+          chunks (chunk) {
+            return !(chunk.name in entries);
+          },
           minChunks: 2,
           minSize: 0,
           test: /^(?!.*[\\\/]node_modules[\\\/]react-intl[\\\/]).+$/,
diff --git a/config/webpacker.yml b/config/webpacker.yml
index 4ad78a190..9accd6152 100644
--- a/config/webpacker.yml
+++ b/config/webpacker.yml
@@ -26,6 +26,7 @@ default: &default
     - .tiff
     - .ico
     - .svg
+    - .gif
     - .eot
     - .otf
     - .ttf