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.rb13
-rw-r--r--config/initializers/statsd.rb2
-rw-r--r--config/locales/devise.zh-CN.yml58
-rw-r--r--config/locales/doorkeeper.zh-CN.yml63
-rw-r--r--config/locales/en.yml10
-rw-r--r--config/locales/ja.yml7
-rw-r--r--config/locales/pl.yml4
-rw-r--r--config/locales/pt-BR.yml22
-rw-r--r--config/locales/simple_form.en.yml1
-rw-r--r--config/locales/simple_form.ja.yml1
-rw-r--r--config/locales/simple_form.pl.yml1
-rw-r--r--config/locales/simple_form.zh-CN.yml6
-rw-r--r--config/locales/zh-CN.yml44
-rw-r--r--config/navigation.rb1
-rw-r--r--config/routes.rb25
-rw-r--r--config/settings.yml5
-rw-r--r--config/themes.yml1
-rw-r--r--config/webpack/configuration.js17
-rw-r--r--config/webpack/generateLocalePacks.js20
-rw-r--r--config/webpack/loaders/babel.js3
-rw-r--r--config/webpack/loaders/sass.js2
-rw-r--r--config/webpack/shared.js31
23 files changed, 230 insertions, 113 deletions
diff --git a/config/application.rb b/config/application.rb
index 0879d3c6a..b54ea1c40 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -9,6 +9,7 @@ Bundler.require(*Rails.groups)
 require_relative '../app/lib/exceptions'
 require_relative '../lib/paperclip/gif_transcoder'
 require_relative '../lib/paperclip/video_transcoder'
+require_relative '../lib/paperclip/audio_transcoder'
 require_relative '../lib/mastodon/snowflake'
 require_relative '../lib/mastodon/version'
 
@@ -70,12 +71,17 @@ module Mastodon
 
     config.active_job.queue_adapter = :sidekiq
 
+    #config.middleware.insert_before 0, Rack::Cors, debug: true, logger: (-> { Rails.logger }) do
     config.middleware.insert_before 0, Rack::Cors do
       allow do
         origins  '*'
         resource '/@:username',  headers: :any, methods: [:get], credentials: false
         resource '/api/*',       headers: :any, methods: [:post, :put, :delete, :get, :patch, :options], credentials: false, expose: ['Link', 'X-RateLimit-Reset', 'X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-Request-Id']
         resource '/oauth/token', 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/environments/production.rb b/config/environments/production.rb
index 5705ffcfe..f7cb4b08a 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -91,9 +91,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',
+    'Content-Security-Policy' => "frame-ancestors 'none'; object-src 'none'; script-src 'self' https://dev-static.glitch.social 'unsafe-inline'; base-uri 'none';" , 
+    'Referrer-Policy'         => 'no-referrer, strict-origin-when-cross-origin',
+    'Strict-Transport-Security' => 'max-age=63072000; includeSubDomains; preload',
+    'X-Clacks-Overhead' => 'GNU Natalie Nguyen'
+
   }
 end
diff --git a/config/initializers/statsd.rb b/config/initializers/statsd.rb
index 17a176174..45702ac94 100644
--- a/config/initializers/statsd.rb
+++ b/config/initializers/statsd.rb
@@ -4,7 +4,7 @@ if ENV['STATSD_ADDR'].present?
   host, port = ENV['STATSD_ADDR'].split(':')
 
   statsd = ::Statsd.new(host, port)
-  statsd.namespace = ['Mastodon', Rails.env].join('.')
+  statsd.namespace = ENV.fetch('STATSD_NAMESPACE') { ['Mastodon', Rails.env].join('.') }
 
   ::NSA.inform_statsd(statsd) do |informant|
     informant.collect(:action_controller, :web)
diff --git a/config/locales/devise.zh-CN.yml b/config/locales/devise.zh-CN.yml
index 8cc814224..0e40fcc90 100644
--- a/config/locales/devise.zh-CN.yml
+++ b/config/locales/devise.zh-CN.yml
@@ -2,24 +2,24 @@
 zh-CN:
   devise:
     confirmations:
-      confirmed: 成功验证您的邮箱地址。
-      send_instructions: 您的电子邮箱将在几分钟后收到一封邮箱确认邮件。
-      send_paranoid_instructions: 如果您的邮箱存在于我们的数据库中,您将收到一封确认帐号的邮件。
+      confirmed: 成功验证你的邮箱地址。
+      send_instructions: 你的电子邮箱将在几分钟后收到一封确认邮件。如果没有,请检查你的垃圾邮箱。
+      send_paranoid_instructions: 如果你的邮箱存在于我们的数据库中,你将收到一封确认注册的邮件。如果没有,请检查你的垃圾邮箱。
     failure:
-      already_authenticated: 您已经登录。
-      inactive: 您还没有激活帐户。
+      already_authenticated: 你已经登录。
+      inactive: 你还没有激活帐户。
       invalid: " %{authentication_keys} 或密码错误。"
-      last_attempt: 您还有最后一次尝试机会,再次失败您的帐号将被锁定。
-      locked: 您的帐号已被锁定。
+      last_attempt: 你还有最后一次尝试机会,再次失败你的帐户将被锁定。
+      locked: 你的帐户已被锁定。
       not_found_in_database: "%{authentication_keys}或密码错误。"
-      timeout: 您已登录超时,请重新登录。
+      timeout: 你已登录超时,请重新登录。
       unauthenticated: 继续操作前请注册或者登录。
-      unconfirmed: 继续操作前请先确认您的帐号。
+      unconfirmed: 继续操作前请先确认你的帐户。
     mailer:
       confirmation_instructions:
         subject: Mastodon 帐户确认信息
       email_changed:
-        subject: Mastodon 电邮已被修改
+        subject: Mastodon 电子邮件地址已被修改
       password_change:
         subject: Mastodon 密码已被重置
       reset_password_instructions:
@@ -30,33 +30,33 @@ zh-CN:
       failure: 由于%{reason},无法从%{kind}获得授权。
       success: 成功地从%{kind}获得授权。
     passwords:
-      no_token: 无重置邮件不可访问密码重置页面。如果您是从重置邮件来到了这个页面,请确保您输入的URL完整的。
-      send_instructions: 几分钟后,您将收到重置密码的电子邮件。
-      send_paranoid_instructions: 如果您的邮箱存在于我们的数据库中,您将收到一封找回密码的邮件。
-      updated: 您的密码已修改成功,您现在已登录。
-      updated_not_active: 您的密码已修改成功。
+      no_token: 你必须通过密码重置邮件才能访问这个页面。如果你确实如此,请确保你输入的 URL 是完整的。
+      send_instructions: 几分钟后,你将收到重置密码的电子邮件。如果没有,请检查你的垃圾邮箱。
+      send_paranoid_instructions: 如果你的邮箱存在于我们的数据库中,你将收到一封找回密码的邮件。如果没有,请检查你的垃圾邮箱。
+      updated: 你的密码已修改成功,你现在已登录。
+      updated_not_active: 你的密码已修改成功。
     registrations:
-      destroyed: 再见!您的帐户已成功注销。我们希望很快可以再见到您。
-      signed_up: 欢迎!您已注册成功。
-      signed_up_but_inactive: 您已注册,但尚未激活帐号。
-      signed_up_but_locked: 您已注册,但帐号被锁定了。
-      signed_up_but_unconfirmed: 一封带有确认链接的邮件已经发送至您的邮箱,请检查邮箱(包括垃圾邮箱),并点击该链接激活您的帐号。
-      update_needs_confirmation: 信息更新成功,但我们需要验证您的新电子邮件地址,请检查邮箱(包括垃圾邮箱),并点击该链接激活您的帐号。
-      updated: 帐号资料更新成功。
+      destroyed: 再见!你的帐户已成功注销。我们希望很快可以再见到你。
+      signed_up: 欢迎!你已注册成功。
+      signed_up_but_inactive: 你已注册,但尚未激活帐户。
+      signed_up_but_locked: 你已注册,但帐户被锁定了。
+      signed_up_but_unconfirmed: 一封带有确认链接的邮件已经发送至你的邮箱,请点击邮件中的链接以激活你的帐户。如果没有,请检查你的垃圾邮箱。
+      update_needs_confirmation: 信息更新成功,但我们需要验证你的新电子邮件地址,请点击邮件中的链接以确认。如果没有,请检查你的垃圾邮箱。
+      updated: 帐户资料更新成功。
     sessions:
-      already_signed_out: 已经退出成功。
+      already_signed_out: 已成功登出。
       signed_in: 登录成功。
-      signed_out: 退出成功。
+      signed_out: 登出成功。
     unlocks:
-      send_instructions: 几分钟后,您将收到一封解锁帐号的邮件。
-      send_paranoid_instructions: 如果您的邮箱存在于我们的数据库中,您将收到一封解锁帐号的邮件。
-      unlocked: 您的帐号已成功解锁,您现在已登录。
+      send_instructions: 几分钟后,你将收到一封解锁帐户的邮件。如果没有,请检查你的垃圾邮箱。
+      send_paranoid_instructions: 如果你的邮箱存在于我们的数据库中,你将收到一封解锁帐户的邮件。如果没有,请检查你的垃圾邮箱。
+      unlocked: 你的帐户已成功解锁。登录以继续。
   errors:
     messages:
       already_confirmed: 已经确认,请重新登录。
-      confirmation_period_expired: 注册帐号后须在%{period}以内确认。请重新注册。
+      confirmation_period_expired: 注册帐户后须在 %{period}以内确认。请重新注册。
       expired: 邮件确认已过期,请重新注册。
       not_found: 找不到。
       not_locked: 未锁定。
       not_saved:
-        other: 发生%{count}个错误,导致%{resource}保存失败:
+        other: 发生 %{count} 个错误,导致%{resource}保存失败:
diff --git a/config/locales/doorkeeper.zh-CN.yml b/config/locales/doorkeeper.zh-CN.yml
index 12b38b81f..c7e8f368d 100644
--- a/config/locales/doorkeeper.zh-CN.yml
+++ b/config/locales/doorkeeper.zh-CN.yml
@@ -3,15 +3,16 @@ zh-CN:
   activerecord:
     attributes:
       doorkeeper/application:
-        name: 名称
-        redirect_uri: 登录回调地址
+        name: 应用名称
+        redirect_uri: 重定向 URI
         scopes: 权限范围
+        website: 应用网站
     errors:
       models:
         doorkeeper/application:
           attributes:
             redirect_uri:
-              fragment_present: 不能包含片段(#)
+              fragment_present: 不能包含网址片段(#)
               invalid_uri: 必须是有效的 URL 格式
               relative_uri: 必须是绝对的 URL 地址
               secured_uri: 必须是 HTTPS/SSL 的 URL 地址
@@ -30,60 +31,65 @@ zh-CN:
       form:
         error: 抱歉! 提交信息的时候遇到了下面的错误
       help:
-        native_redirect_uri: 使用 %{native_redirect_uri} 作为本地测试
+        native_redirect_uri: 本地测试请使用 %{native_redirect_uri}
         redirect_uri: 每行只能有一个 URL
-        scopes: 用空格隔开权限范围,留空则使用默认设置
+        scopes: 用空格分割权限范围,留空则使用默认设置
       index:
-        callback_url: 登录回调地址
+        application: 应用
+        callback_url: 回调 URL
+        delete: 删除
         name: 名称
         new: 创建新应用
+        scopes: 权限范围
+        show: 显示
         title: 你的应用
       new:
         title: 创建新应用
       show:
         actions: 操作
         application_id: 应用 ID
-        callback_urls: 登录回调地址
+        callback_urls: 回调 URL
         scopes: 权限范围
-        secret: 私钥
+        secret: 应用密钥
         title: 应用:%{name}
     authorizations:
       buttons:
-        authorize: 授权
-        deny: 拒绝
+        authorize: 同意授权
+        deny: 拒绝授权
       error:
-        title: 存在错误
+        title: 发生错误
       new:
-        able_to: 此应用将会
-        prompt: 授权 %{client_name} 使用你的帐号?
-        title: 需要你授权
+        able_to: 此应用将能够
+        prompt: 授权 %{client_name} 使用你的帐户?
+        title: 需要授权
       show:
-        title: Copy this authorization code and paste it to the application.
+        title: 接下来请复制此处的授权代码并粘贴到应用中。
     authorized_applications:
       buttons:
-        revoke: 注销
+        revoke: 撤销授权
       confirmations:
-        revoke: 确定要注销此应用的认证信息吗?
+        revoke: 确定要撤销对此应用的授权吗?
       index:
         application: 应用
         created_at: 授权时间
         date_format: "%Y-%m-%d %H:%M:%S"
-        title: 你授权的应用列表
+        scopes: 权限范围
+        title: 已授权的应用列表
     errors:
       messages:
         access_denied: 用户或服务器拒绝了请求
-        credential_flow_not_configured: Resource Owner Password Credentials flow failed,原因是 Doorkeeper.configure.resource_owner_from_credentials 尚未设置。
-        invalid_client: 由于未知、不支持或没有客户端,认证失败
+        credential_flow_not_configured: 由于 Doorkeeper.configure.resource_owner_from_credentials 尚未配置,应用验证授权流程失败。
+        invalid_client: 由于应用信息未知、未提交认证信息或使用了不支持的认证方式,认证失败
         invalid_grant: 授权方式无效,或者登录回调地址无效、过期或已被撤销
         invalid_redirect_uri: 无效的登录回调地址
-        invalid_request: 这个请求缺少必要的参数,或者参数值、格式不正确
-        invalid_resource_owner: 资源所有者认证无效或没有所有者
-        invalid_scope: 请求范围无效、未知或格式不正确
+        invalid_request: 请求缺少必要的参数,或者参数值、格式不正确
+        invalid_resource_owner: 资源所有者认证无效,或找不到所有者
+        invalid_scope: 请求的权限范围无效、未知或格式不正确
         invalid_token:
           expired: 访问令牌已过期
           revoked: 访问令牌已被吊销
           unknown: 访问令牌无效
-        resource_owner_authenticator_not_configured: Resource Owner find failed,原因是 Doorkeeper.configure.resource_owner_authenticator 尚未设置。
+        resource_owner_authenticator_not_configured: 由于 Doorkeeper.configure.resource_owner_authenticator 尚未配置,查找资源所有者失败。
         server_error: 服务器异常,无法处理请求
         temporarily_unavailable: 服务器维护中或负载过高,暂时无法处理请求
         unauthorized_client: 未授权的应用,请求无法执行
@@ -99,16 +105,15 @@ zh-CN:
           notice: 应用修改成功
       authorized_applications:
         destroy:
-          notice: 已成功注销了应用的认证信息
+          notice: 已成功撤销对此应用的授权
     layouts:
       admin:
         nav:
           applications: 应用
-          home: 首页
           oauth2_provider: OAuth2 提供商
       application:
-        title: OAuth 认证
+        title: 需要 OAuth 认证
     scopes:
-      follow: 关注(或取消关注),屏蔽(或取消屏蔽)用户
-      read: 读取你的账户数据
+      follow: 关注(或取消关注)、屏蔽(或取消屏蔽)用户
+      read: 读取你的帐户数据
       write: 为你发表嘟文
diff --git a/config/locales/en.yml b/config/locales/en.yml
index e94165317..cebf704ce 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -48,6 +48,7 @@ en:
     reserved_username: The username is reserved
     roles:
       admin: Admin
+      moderator: Mod
     unfollow: Unfollow
   admin:
     account_moderation_notes:
@@ -393,6 +394,14 @@ en:
       muting: Muting list
     upload: Upload
   in_memoriam_html: In Memoriam.
+  keyword_mutes:
+    add_keyword: Add keyword
+    edit: Edit
+    edit_keyword: Edit keyword
+    keyword: Keyword
+    match_whole_word: Match whole word
+    remove: Remove
+    remove_all: Remove all
   landing_strip_html: "<strong>%{name}</strong> is a user on %{link_to_root_path}. You can follow them or interact with them if you have an account anywhere in the fediverse."
   landing_strip_signup_html: If you don't, you can <a href="%{sign_up_path}">sign up here</a>.
   media_attachments:
@@ -511,6 +520,7 @@ en:
     export: Data export
     followers: Authorized followers
     import: Import
+    keyword_mutes: Muted keywords
     notifications: Notifications
     preferences: Preferences
     settings: Settings
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 63a2495cb..82b642b5b 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -62,6 +62,7 @@ ja:
       by_domain: ドメイン
       confirm: 確認
       confirmed: 確認済み
+      demote: 降格
       disable: 無効化
       disable_two_factor_authentication: 二段階認証を無効にする
       disabled: 無効
@@ -101,6 +102,7 @@ ja:
       outbox_url: Outbox URL
       perform_full_suspension: 完全に活動停止させる
       profile_url: プロフィールURL
+      promote: 昇格
       protocol: プロトコル
       public: パブリック
       push_subscription_expires: PuSH購読期限
@@ -108,6 +110,11 @@ ja:
       reset: リセット
       reset_password: パスワード再設定
       resubscribe: 再講読
+      role: 役割
+      roles:
+        admin: 管理者
+        moderator: モデレーター
+        user: ユーザー
       salmon_url: Salmon URL
       search: 検索
       shared_inbox_url: Shared Inbox URL
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index d20396810..49dace354 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -9,7 +9,7 @@ pl:
     contact_missing: Nie ustawiono
     contact_unavailable: Nie dotyczy
     description_headline: Czym jest %{domain}?
-    domain_count_after: instancji
+    domain_count_after: instancjami
     domain_count_before: Serwer połączony z
     extended_description_html: |
       <h3>Dobre miejsce na zasady użytkowania</h3>
@@ -629,7 +629,7 @@ pl:
     manual_instructions: 'Jeżeli nie możesz zeskanować kodu QR, musisz wprowadzić ten kod ręcznie:'
     recovery_codes: Przywróć kody zapasowe
     recovery_codes_regenerated: Pomyślnie wygenerowano ponownie kody zapasowe
-    recovery_instructions_html: Jeżeli kiedykolwiek utracisz dostęp do telefonu, możesz wykorzystać jeden z kodów zapasowych, aby odzyskać dostęp do konta. <strong>Trzymaj je w bezpiecznym miejscu</strong>. Na przykład, wydrukuj je i przechowuj z ważnymu dokumentami.
+    recovery_instructions_html: Jeżeli kiedykolwiek utracisz dostęp do telefonu, możesz wykorzystać jeden z kodów zapasowych, aby odzyskać dostęp do konta. <strong>Trzymaj je w bezpiecznym miejscu</strong>. Na przykład, wydrukuj je i przechowuj z ważnymi dokumentami.
     setup: Skonfiguruj
     wrong_code: Wprowadzony kod jest niepoprawny! Czy czas serwera i urządzenia jest poprawny?
   users:
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 4b9ea152f..f5c61c01c 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -43,7 +43,7 @@ pt-BR:
     people_followed_by: Pessoas que %{name} segue
     people_who_follow: Pessoas que seguem %{name}
     posts: Toots
-    posts_with_replies: Toots com respostas
+    posts_with_replies: Toots e respostas
     remote_follow: Siga remotamente
     reserved_username: Este usuário está reservado
     roles:
@@ -59,13 +59,19 @@ pt-BR:
       destroyed_msg: Nota de moderação excluída com sucesso!
     accounts:
       are_you_sure: Você tem certeza?
+      by_domain: Domínio
       confirm: Confirmar
       confirmed: Confirmado
+      demote: Rebaixar
+      disable: Desativar
       disable_two_factor_authentication: Desativar 2FA
+      disabled: Desativado
       display_name: Nome de exibição
       domain: Domínio
       edit: Editar
       email: E-mail
+      enable: Ativar
+      enabled: Ativado
       feed_url: URL do feed
       followers: Seguidores
       followers_url: URL de seguidores
@@ -77,7 +83,9 @@ pt-BR:
         local: Local
         remote: Remoto
         title: Localização
+      login_status: Status de login
       media_attachments: Mídia(s) anexada(s)
+      memorialize: Tornar um memorial
       moderation:
         all: Todos
         silenced: Silenciados
@@ -94,6 +102,7 @@ pt-BR:
       outbox_url: URL da Outbox
       perform_full_suspension: Efetue suspensão total
       profile_url: URL do perfil
+      promote: Promover
       protocol: Protocolo
       public: Público
       push_subscription_expires: Inscrição PuSH expira
@@ -101,6 +110,11 @@ pt-BR:
       reset: Anular
       reset_password: Modificar senha
       resubscribe: Reinscrever-se
+      role: Permissões
+      roles:
+        admin: Administrador
+        moderator: Moderador
+        user: Usuário
       salmon_url: Salmon URL
       search: Pesquisar
       shared_inbox_url: URL da Inbox Compartilhada
@@ -130,11 +144,16 @@ pt-BR:
       enable: Habilitar
       enabled_msg: Emoji habilitado com sucesso!
       image_hint: PNG de até 50KB
+      listed: Listado
       new:
         title: Adicionar novo emoji customizado
+      overwrite: Sobrescrever
       shortcode: Atalho
       shortcode_hint: Pelo menos 2 caracteres, apenas caracteres alfanuméricos e underscores
       title: Emojis customizados
+      unlisted: Não listado
+      update_failed_msg: Não foi possível atualizar esse emoji
+      updated_msg: Emoji atualizado com sucesso!
       upload: Enviar
     domain_blocks:
       add_new: Adicionar novo
@@ -373,6 +392,7 @@ pt-BR:
       following: Pessoas que você segue
       muting: Lista de silêncio
     upload: Enviar
+  in_memoriam_html: Em memória de
   landing_strip_html: "<strong>%{name}</strong> é um usuário no %{link_to_root_path}. Você pode segui-lo ou interagir com ele se você tiver uma conta em qualquer lugar no fediverso."
   landing_strip_signup_html: Se não, você pode <a href="%{sign_up_path}">se cadastrar aqui</a>.
   media_attachments:
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index aafae48ce..faf41f316 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -54,6 +54,7 @@ en:
       interactions:
         must_be_follower: Block notifications from non-followers
         must_be_following: Block notifications from people you don't follow
+        must_be_following_dm: Block direct messages from people you don't follow
       notification_emails:
         digest: Send digest e-mails
         favourite: Send e-mail when someone favourites your status
diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml
index 993eae706..48eaf79b2 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -50,6 +50,7 @@ ja:
       interactions:
         must_be_follower: フォロワー以外からの通知をブロック
         must_be_following: フォローしていないユーザーからの通知をブロック
+        must_be_following_dm: フォローしていないユーザーからのダイレクトメッセージをブロック
       notification_emails:
         digest: タイムラインからピックアップしてメールで通知する
         favourite: お気に入りに登録された時にメールで通知する
diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml
index 68f84d109..8b539662c 100644
--- a/config/locales/simple_form.pl.yml
+++ b/config/locales/simple_form.pl.yml
@@ -58,6 +58,7 @@ pl:
       interactions:
         must_be_follower: Nie wyświetlaj powiadomień od osób, które Cię nie śledzą
         must_be_following: Nie wyświetlaj powiadomień od osób, których nie śledzisz
+        must_be_following_dm: Nie wyświetlaj wiadomości bezpośrednich od osób, których nie śledzisz
       notification_emails:
         digest: Wysyłaj podsumowania e-mailem
         favourite: Powiadamiaj mnie e-mailem, gdy ktoś polubi mój wpis
diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml
index 8bd3b576c..f8c9461ad 100644
--- a/config/locales/simple_form.zh-CN.yml
+++ b/config/locales/simple_form.zh-CN.yml
@@ -8,13 +8,13 @@ zh-CN:
         display_name: 还能输入 <span class="name-counter">%{count}</span> 个字符
         header: 文件大小限制 2MB,只支持 PNG、GIF 或 JPG 格式。图片分辨率将会压缩至 700×335px
         locked: 你需要手动审核所有关注请求
-        note: 还能输入 <span class="name-counter">%{count}</span> 个字符
+        note: 还能输入 <span class="note-counter">%{count}</span> 个字符
         setting_noindex: 此设置会影响到你的公开个人资料以及嘟文页面
         setting_theme: 此设置会影响到你从任意设备登录时 Mastodon 的显示样式
       imports:
         data: 请上传从其他 Mastodon 实例导出的 CSV 文件
       sessions:
-        otp: 输入你手机上生成的两步验证码,或者任意一个恢复代码。
+        otp: 输入你手机上生成的双重认证码,或者任意一个恢复代码。
       user:
         filtered_languages: 勾选语言的嘟文将不会出现在你的公共时间轴上
     labels:
@@ -32,7 +32,7 @@ zh-CN:
         locked: 保护你的帐户(锁嘟)
         new_password: 新密码
         note: 简介
-        otp_attempt: 两步认证代码
+        otp_attempt: 双重认证代码
         password: 密码
         setting_auto_play_gif: 自动播放 GIF 动画
         setting_boost_modal: 在转嘟前询问我
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 4a71a9959..b50c34fd0 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -59,13 +59,19 @@ zh-CN:
       destroyed_msg: 管理记录删除成功!
     accounts:
       are_you_sure: 你确定吗?
+      by_domain: 域名
       confirm: 确认
       confirmed: 已确认
-      disable_two_factor_authentication: 停用两步认证
+      demote: 降任
+      disable: 停用
+      disable_two_factor_authentication: 停用双重认证
+      disabled: 已停用
       display_name: 昵称
       domain: 域名
       edit: 编辑
       email: 电子邮件地址
+      enable: 启用
+      enabled: 已启用
       feed_url: 订阅 URL
       followers: 关注者
       followers_url: 关注者(Followers)URL
@@ -77,7 +83,9 @@ zh-CN:
         local: 本地
         remote: 远程
         title: 位置
+      login_status: 登录状态
       media_attachments: 媒体文件
+      memorialize: 设置为追悼帐户
       moderation:
         all: 全部
         silenced: 已静音
@@ -94,6 +102,7 @@ zh-CN:
       outbox_url: 发件箱(Outbox)URL
       perform_full_suspension: 永久封禁
       profile_url: 个人资料页面 URL
+      promote: 升任
       protocol: 协议
       public: 公开页面
       push_subscription_expires: PuSH 订阅过期时间
@@ -101,6 +110,11 @@ zh-CN:
       reset: 重置
       reset_password: 重置密码
       resubscribe: 重新订阅
+      role: 用户组
+      roles:
+        admin: 管理员
+        moderator: 协管
+        user: 用户
       salmon_url: Salmon URL
       search: 搜索
       shared_inbox_url: 公用收件箱(Shared Inbox)URL
@@ -130,18 +144,19 @@ zh-CN:
       enable: 启用
       enabled_msg: 表情启用成功
       image_hint: PNG 格式,最大 50KB
-      listed: 默认显示的表情
+      listed: 已显示
       new:
         title: 添加新的自定义表情
+      overwrite: 覆盖
       shortcode: 短代码
       shortcode_hint: 至少 2 个字符,只能使用字母、数字和下划线
       title: 自定义表情
-      unlisted: 默认隐藏的表情
+      unlisted: 已隐藏
       update_failed_msg: 表情更新失败!
       updated_msg: 表情更新成功!
       upload: 上传
     domain_blocks:
-      add_new: 添加
+      add_new: 添加新条目
       created_msg: 正在进行域名屏蔽
       destroyed_msg: 域名屏蔽已撤销
       domain: 域名
@@ -149,7 +164,7 @@ zh-CN:
         create: 添加域名屏蔽
         hint: 域名屏蔽不会阻止该域名下的帐户进入本站的数据库,但是会对来自这个域名的帐户自动进行预先设置的管理操作。
         severity:
-          desc_html: 选择<strong>自动静音</strong>会将该域名下帐户发送的嘟文设置为仅关注者可见;选择<strong>自动封禁</strong>会将该域名下帐户发送的嘟文、媒体文件以及个人资料数据从本实例上删除;选择<strong>无</strong>可以拒绝接收来自该域名的任何媒体文件。
+          desc_html: 选择<strong>自动静音</strong>会将该域名下帐户发送的嘟文设置为仅关注者可见;选择<strong>自动封禁</strong>会将该域名下帐户发送的嘟文、媒体文件以及个人资料数据从本实例上删除;如果你只是想拒绝接收来自该域名的任何媒体文件,请选择<strong>无</strong>。
           noop: 无
           silence: 自动静音
           suspend: 自动封禁
@@ -160,7 +175,7 @@ zh-CN:
         noop: 无
         silence: 自动静音
         suspend: 自动封禁
-      severity: 封禁级别
+      severity: 屏蔽级别
       show:
         affected_accounts: 将会影响到数据库中的 %{count} 个帐户
         retroactive:
@@ -177,7 +192,7 @@ zh-CN:
       destroyed_msg: 电子邮件域名屏蔽删除成功
       domain: 域名
       new:
-        create: 添加封禁
+        create: 添加屏蔽
         title: 添加电子邮件域名屏蔽
       title: 电子邮件域名屏蔽
     instances:
@@ -373,6 +388,7 @@ zh-CN:
       following: 关注列表
       muting: 静音列表
     upload: 上传
+  in_memoriam_html: 谨此悼念。
   landing_strip_html: "<strong>%{name}</strong> 是一位来自 %{link_to_root_path} 的用户。如果你想关注这个人或者与这个人互动,你需要在任意一个 Mastodon 实例或与其兼容的网站上拥有一个帐户。"
   landing_strip_signup_html: 还没有这种帐户?你可以<a href="%{sign_up_path}">在本站注册一个</a>。
   media_attachments:
@@ -492,7 +508,7 @@ zh-CN:
     notifications: 通知
     preferences: 首选项
     settings: 设置
-    two_factor_authentication: 两步认证
+    two_factor_authentication: 双重认证
     your_apps: 你的应用
   statuses:
     open_in_web: 在站内打开
@@ -589,16 +605,16 @@ zh-CN:
     default: Mastodon
   time:
     formats:
-      default: "%Y年%-m月%d日%H:%M"
+      default: "%Y年%-m月%d日 %H:%M"
   two_factor_authentication:
     code_hint: 输入你的认证器生成的代码以确认
-    description_html: 启用<strong>两步认证</strong>后,你需要输入手机认证器生成的代码才能登录
+    description_html: 启用<strong>双重认证</strong>后,你需要输入手机认证器生成的代码才能登录
     disable: 停用
     enable: 启用
-    enabled: 两步认证已启用
-    enabled_success: 两步认证启用成功
+    enabled: 双重认证已启用
+    enabled_success: 双重认证启用成功
     generate_recovery_codes: 生成恢复代码
-    instructions_html: "<strong>请使用 Google 身份验证器或其他类似的 TOTP 两步验证手机应用扫描此处的二维码</strong>。启用两部验证后,你需要输入该应用生成的代码来登录你的帐户。"
+    instructions_html: "<strong>请使用 Google 身份验证器或其他 TOTP 双重认证手机应用扫描此处的二维码</strong>。启用双重认证后,你需要输入该应用生成的代码来登录你的帐户。"
     lost_recovery_codes: 如果你的手机不慎丢失,你可以使用恢复代码来重新获得对帐户的访问权。如果你遗失了恢复代码,可以在此处重新生成。之前使用的恢复代码将会失效。
     manual_instructions: 如果你无法扫描二维码,请手动输入下列文本:
     recovery_codes: 备份恢复代码
@@ -608,5 +624,5 @@ zh-CN:
     wrong_code: 输入的认证码无效!请检查你设备上显示的时间是否正确,如果正确,你可能需要联系管理员以检查服务器的时间是否正确。
   users:
     invalid_email: 输入的电子邮件地址无效
-    invalid_otp_token: 输入的两步认证代码无效
+    invalid_otp_token: 输入的双重认证代码无效
     signed_in_as: 当前登录的帐户:
diff --git a/config/navigation.rb b/config/navigation.rb
index 5b4800f07..16c48849b 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -7,6 +7,7 @@ SimpleNavigation::Configuration.run do |navigation|
     primary.item :settings, safe_join([fa_icon('cog fw'), t('settings.settings')]), settings_profile_url do |settings|
       settings.item :profile, safe_join([fa_icon('user fw'), t('settings.edit_profile')]), settings_profile_url
       settings.item :preferences, safe_join([fa_icon('sliders fw'), t('settings.preferences')]), settings_preferences_url
+      settings.item :keyword_mutes, safe_join([fa_icon('volume-off fw'), t('settings.keyword_mutes')]), settings_keyword_mutes_url
       settings.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_notifications_url
       settings.item :password, safe_join([fa_icon('lock fw'), t('auth.change_password')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete}
       settings.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_url, highlights_on: %r{/settings/two_factor_authentication}
diff --git a/config/routes.rb b/config/routes.rb
index 9301a4e50..36acd428d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -66,6 +66,13 @@ Rails.application.routes.draw do
 
   namespace :settings do
     resource :profile, only: [:show, :update]
+
+    resources :keyword_mutes do
+      collection do
+        delete :destroy_all
+      end
+    end
+
     resource :preferences, only: [:show, :update]
     resource :notifications, only: [:show, :update]
     resource :import, only: [:show, :create]
@@ -161,7 +168,13 @@ Rails.application.routes.draw do
     resources :account_moderation_notes, only: [:create, :destroy]
   end
 
-  get '/admin', to: redirect('/admin/settings/edit', status: 302)
+  authenticate :user, lambda { |u| u.admin? } do
+    get '/admin', to: redirect('/admin/settings/edit', status: 302)
+  end
+
+  authenticate :user, lambda { |u| u.moderator? } do
+    get '/admin', to: redirect('/admin/reports', status: 302)
+  end
 
   namespace :api do
     # PubSubHubbub outgoing subscriptions
@@ -203,6 +216,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
@@ -216,7 +230,11 @@ Rails.application.routes.draw do
       resources :follows,    only: [:create]
       resources :media,      only: [:create, :update]
       resources :blocks,     only: [:index]
-      resources :mutes,      only: [:index]
+      resources :mutes,      only: [:index] do
+        collection do 
+          get 'details'
+        end
+      end
       resources :favourites, only: [:index]
       resources :reports,    only: [:index, :create]
 
@@ -236,10 +254,11 @@ Rails.application.routes.draw do
         end
       end
 
-      resources :notifications, only: [:index, :show] do
+      resources :notifications, only: [:index, :show, :destroy] do
         collection do
           post :clear
           post :dismiss
+          delete :destroy_multiple
         end
       end
 
diff --git a/config/settings.yml b/config/settings.yml
index 11681d7ec..1b8a6673e 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -7,7 +7,7 @@
 # For more information, see docs/Running-Mastodon/Administration-guide.md
 #
 defaults: &defaults
-  site_title: Mastodon
+  site_title: 'dev.glitch.social'
   site_description: ''
   site_extended_description: ''
   site_terms: ''
@@ -16,7 +16,7 @@ defaults: &defaults
   open_registrations: true
   closed_registrations_message: ''
   open_deletion: true
-  timeline_preview: true
+  timeline_preview: false
   default_sensitive: false
   unfollow_modal: false
   boost_modal: false
@@ -36,6 +36,7 @@ defaults: &defaults
   interactions:
     must_be_follower: false
     must_be_following: false
+    must_be_following_dm: false
   reserved_usernames:
     - admin
     - support
diff --git a/config/themes.yml b/config/themes.yml
deleted file mode 100644
index a1049fae7..000000000
--- a/config/themes.yml
+++ /dev/null
@@ -1 +0,0 @@
-default: styles/application.scss
diff --git a/config/webpack/configuration.js b/config/webpack/configuration.js
index 822329490..74f75d89b 100644
--- a/config/webpack/configuration.js
+++ b/config/webpack/configuration.js
@@ -1,16 +1,27 @@
 // Common configuration for webpacker loaded from config/webpacker.yml
 
-const { join, resolve } = require('path');
+const { basename, dirname, join, resolve } = require('path');
 const { env } = require('process');
 const { safeLoad } = require('js-yaml');
 const { readFileSync } = require('fs');
+const glob = require('glob');
 
 const configPath = resolve('config', 'webpacker.yml');
 const loadersDir = join(__dirname, 'loaders');
 const settings = safeLoad(readFileSync(configPath), 'utf8')[env.NODE_ENV];
+const themeFiles = glob.sync('app/javascript/themes/*/theme.yml');
+const themes = {};
 
-const themePath = resolve('config', 'themes.yml');
-const themes = safeLoad(readFileSync(themePath), 'utf8');
+for (let i = 0; i < themeFiles.length; i++) {
+  const themeFile = themeFiles[i];
+  const data = safeLoad(readFileSync(themeFile), 'utf8');
+  if (!data.pack_directory) {
+    data.pack_directory = dirname(themeFile);
+  }
+  if (data.pack) {
+    themes[basename(dirname(themeFile))] = data;
+  }
+}
 
 function removeOuterSlashes(string) {
   return string.replace(/^\/*/, '').replace(/\/*$/, '');
diff --git a/config/webpack/generateLocalePacks.js b/config/webpack/generateLocalePacks.js
index b71cf2ade..cd3bed50c 100644
--- a/config/webpack/generateLocalePacks.js
+++ b/config/webpack/generateLocalePacks.js
@@ -34,6 +34,23 @@ locales.forEach(locale => {
   ].filter(filename => fs.existsSync(path.join(outPath, filename)))
     .map(filename => filename.replace(/..\/..\/node_modules\//, ''))[0];
 
+  let glitchInject = `
+const mergedMessages = messages;
+`;
+
+  const glitchPath = `../../app/javascript/glitch/locales/${locale}.json`;
+  if (fs.existsSync(path.join(outPath, glitchPath))) {
+    glitchInject = `
+import glitchMessages from ${JSON.stringify(glitchPath)};
+
+let mergedMessages = messages;
+Object.keys(glitchMessages).forEach(function (key) {
+   mergedMessages[key] = glitchMessages[key];
+});
+
+`;
+  }
+
   const localeContent = `//
 // locale_${locale}.js
 // automatically generated by generateLocalePacks.js
@@ -41,7 +58,8 @@ locales.forEach(locale => {
 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});
+${glitchInject}
+setLocale({messages: mergedMessages, localeData: localeData});
 `;
   fs.writeFileSync(localePath, localeContent, 'utf8');
   outPaths.push(localePath);
diff --git a/config/webpack/loaders/babel.js b/config/webpack/loaders/babel.js
index e17d2fa70..770c89aa7 100644
--- a/config/webpack/loaders/babel.js
+++ b/config/webpack/loaders/babel.js
@@ -7,7 +7,8 @@ module.exports = {
   exclude: /node_modules/,
   loader: 'babel-loader',
   options: {
-    forceEnv: env,
+    forceEnv: process.env.NODE_ENV || 'development',
+    sourceRoot: 'app/javascript',
     cacheDirectory: env === 'development' ? false : resolve(__dirname, '..', '..', '..', 'tmp', 'cache', 'babel-loader'),
   },
 };
diff --git a/config/webpack/loaders/sass.js b/config/webpack/loaders/sass.js
index 88d94c684..96ad7abe8 100644
--- a/config/webpack/loaders/sass.js
+++ b/config/webpack/loaders/sass.js
@@ -9,7 +9,7 @@ module.exports = {
       { loader: 'css-loader', options: { minimize: env.NODE_ENV === 'production' } },
       { loader: 'postcss-loader', options: { sourceMap: true } },
       'resolve-url-loader',
-      'sass-loader',
+      { loader: 'sass-loader', options: { includePaths: ['app/javascript'] } },
     ],
   }),
 };
diff --git a/config/webpack/shared.js b/config/webpack/shared.js
index 50fa48175..5d176db4e 100644
--- a/config/webpack/shared.js
+++ b/config/webpack/shared.js
@@ -1,7 +1,7 @@
 // Note: You must restart bin/webpack-dev-server for changes to take effect
 
 const webpack = require('webpack');
-const { basename, dirname, join, relative, resolve, sep } = require('path');
+const { basename, dirname, join, relative, resolve } = require('path');
 const { sync } = require('glob');
 const ExtractTextPlugin = require('extract-text-webpack-plugin');
 const ManifestPlugin = require('webpack-manifest-plugin');
@@ -26,10 +26,13 @@ module.exports = {
       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;
-    }, {})
+    Object.keys(themes).reduce(
+      (themePaths, name) => {
+        const themeData = themes[name];
+        themePaths[`themes/${name}`] = resolve(themeData.pack_directory, themeData.pack);
+        return themePaths;
+      }, {}
+    )
   ),
 
   output: {
@@ -52,25 +55,17 @@ module.exports = {
         resource.request = resource.request.replace(/^history/, 'history/es');
       }
     ),
-    new ExtractTextPlugin(env.NODE_ENV === 'production' ? '[name]-[contenthash].css' : '[name].css'),
+    new ExtractTextPlugin({
+      filename: env.NODE_ENV === 'production' ? '[name]-[contenthash].css' : '[name].css',
+      allChunks: true,
+    }),
     new ManifestPlugin({
       publicPath: output.publicPath,
       writeToFileEmit: true,
     }),
     new webpack.optimize.CommonsChunkPlugin({
       name: 'common',
-      minChunks: (module, count) => {
-        const reactIntlPathRegexp = new RegExp(`node_modules\\${sep}react-intl`);
-
-        if (module.resource && reactIntlPathRegexp.test(module.resource)) {
-          // skip react-intl because it's useless to put in the common chunk,
-          // e.g. because "shared" modules between zh-TW and zh-CN will never
-          // be loaded together
-          return false;
-        }
-
-        return count >= 2;
-      },
+      minChunks: Infinity, // It doesn't make sense to use common chunks with multiple frontend support.
     }),
   ],