diff --git a/CHANGELOG.md b/CHANGELOG.md
index 133a2770..5555a63c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,10 +4,17 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ## [Unreleased]
-## [Unreleased patch]
+
+## [2.1.1] - 2020-09-08
+### Changed
+- Polls will be hidden with status content if "Collapse posts with subjects" is enabled and the post is collapsed.
+
+### Fixed
+- Autocomplete won't stop at the second @, so it'll still work with "@lain@l" and not start over.
+- Fixed weird autocomplete behavior when you write ":custom_emoji: ?"
 
 ## [2.1.0] - 2020-08-28
-### Add
+### Added
 - Autocomplete domains from list of known instances
 - 'Bot' settings option and badge
 - Added profile meta data fields that can be set in profile settings
@@ -51,7 +58,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Multiple issues with muted statuses/notifications
 
 ## [2.0.5] - 2020-05-12
-### Add
+### Added
 - Added private notifications option for push notifications
 - 'Copy link' button for statuses (in the ellipsis menu)
 
@@ -69,7 +76,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ### Changed
 - Emoji autocomplete will match any part of the word and not just start, for example :drool will now helpfully suggest :blobcatdrool: and :blobcatdroolreach:
 
-### Add
+### Added
 - Follow request notification support
 
 ## [2.0.2] - 2020-04-08
diff --git a/src/components/password_reset/password_reset.js b/src/components/password_reset/password_reset.js
index 62e74e30..5d21d720 100644
--- a/src/components/password_reset/password_reset.js
+++ b/src/components/password_reset/password_reset.js
@@ -47,11 +47,6 @@ const passwordReset = {
         if (status === 204) {
           this.success = true
           this.error = null
-        } else if (status === 404 || status === 400) {
-          this.error = this.$t('password_reset.not_found')
-          this.$nextTick(() => {
-            this.$refs.email.focus()
-          })
         } else if (status === 429) {
           this.throttled = true
           this.error = this.$t('password_reset.too_many_requests')
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index e7094bec..ad149506 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -555,6 +555,9 @@ const PostStatusForm = {
     },
     updateIdempotencyKey () {
       this.idempotencyKey = Date.now().toString()
+    },
+    openProfileTab () {
+      this.$store.dispatch('openSettingsModalTab', 'profile')
     }
   }
 }
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index 520c03ea..d67d9ae9 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -23,9 +23,12 @@
           tag="p"
           class="visibility-notice"
         >
-          <router-link :to="{ name: 'user-settings' }">
+          <a
+            href="#"
+            @click="openProfileTab"
+          >
             {{ $t('post_status.account_not_locked_warning_link') }}
-          </router-link>
+          </a>
         </i18n>
         <p
           v-if="!hideScopeNotice && newStatus.visibility === 'public'"
diff --git a/src/components/settings_modal/settings_modal_content.js b/src/components/settings_modal/settings_modal_content.js
index 48101a90..ef1a5ffa 100644
--- a/src/components/settings_modal/settings_modal_content.js
+++ b/src/components/settings_modal/settings_modal_content.js
@@ -27,6 +27,34 @@ const SettingsModalContent = {
   computed: {
     isLoggedIn () {
       return !!this.$store.state.users.currentUser
+    },
+    open () {
+      return this.$store.state.interface.settingsModalState !== 'hidden'
+    }
+  },
+  methods: {
+    onOpen () {
+      const targetTab = this.$store.state.interface.settingsModalTargetTab
+      // We're being told to open in specific tab
+      if (targetTab) {
+        const tabIndex = this.$refs.tabSwitcher.$slots.default.findIndex(elm => {
+          return elm.data && elm.data.attrs['data-tab-name'] === targetTab
+        })
+        if (tabIndex >= 0) {
+          this.$refs.tabSwitcher.setTab(tabIndex)
+        }
+      }
+      // Clear the state of target tab, so that next time settings is opened
+      // it doesn't force it.
+      this.$store.dispatch('clearSettingsModalTargetTab')
+    }
+  },
+  mounted () {
+    this.onOpen()
+  },
+  watch: {
+    open: function (value) {
+      if (value) this.onOpen()
     }
   }
 }
diff --git a/src/components/settings_modal/settings_modal_content.vue b/src/components/settings_modal/settings_modal_content.vue
index 2156844f..bc30a0ff 100644
--- a/src/components/settings_modal/settings_modal_content.vue
+++ b/src/components/settings_modal/settings_modal_content.vue
@@ -8,6 +8,7 @@
     <div
       :label="$t('settings.general')"
       icon="wrench"
+      data-tab-name="general"
     >
       <GeneralTab />
     </div>
@@ -15,6 +16,7 @@
       v-if="isLoggedIn"
       :label="$t('settings.profile_tab')"
       icon="user"
+      data-tab-name="profile"
     >
       <ProfileTab />
     </div>
@@ -22,18 +24,21 @@
       v-if="isLoggedIn"
       :label="$t('settings.security_tab')"
       icon="lock"
+      data-tab-name="security"
     >
       <SecurityTab />
     </div>
     <div
       :label="$t('settings.filtering')"
       icon="filter"
+      data-tab-name="filtering"
     >
       <FilteringTab />
     </div>
     <div
       :label="$t('settings.theme')"
       icon="brush"
+      data-tab-name="theme"
     >
       <ThemeTab />
     </div>
@@ -41,6 +46,7 @@
       v-if="isLoggedIn"
       :label="$t('settings.notifications')"
       icon="bell-ringing-o"
+      data-tab-name="notifications"
     >
       <NotificationsTab />
     </div>
@@ -48,6 +54,7 @@
       v-if="isLoggedIn"
       :label="$t('settings.data_import_export_tab')"
       icon="download"
+      data-tab-name="dataImportExport"
     >
       <DataImportExportTab />
     </div>
@@ -56,12 +63,14 @@
       :label="$t('settings.mutes_and_blocks')"
       :fullHeight="true"
       icon="eye-off"
+      data-tab-name="mutesAndBlocks"
     >
       <MutesAndBlocksTab />
     </div>
     <div
       :label="$t('settings.version.title')"
       icon="info-circled"
+      data-tab-name="version"
     >
       <VersionTab />
     </div>
diff --git a/src/components/status_content/status_content.vue b/src/components/status_content/status_content.vue
index fb469a2f..76fe3278 100644
--- a/src/components/status_content/status_content.vue
+++ b/src/components/status_content/status_content.vue
@@ -71,6 +71,10 @@
           v-if="attachmentTypes.includes('unknown')"
           class="icon-doc"
         />
+        <span
+          v-if="status.poll && status.poll.options"
+          class="icon-chart-bar"
+        />
         <span
           v-if="status.card"
           class="icon-link"
@@ -86,7 +90,7 @@
       </a>
     </div>
 
-    <div v-if="status.poll && status.poll.options">
+    <div v-if="status.poll && status.poll.options && !hideSubjectStatus">
       <poll :base-poll="status.poll" />
     </div>
 
diff --git a/src/components/tab_switcher/tab_switcher.js b/src/components/tab_switcher/tab_switcher.js
index 40b5b3ca..9c1da354 100644
--- a/src/components/tab_switcher/tab_switcher.js
+++ b/src/components/tab_switcher/tab_switcher.js
@@ -60,16 +60,19 @@ export default Vue.component('tab-switcher', {
     }
   },
   methods: {
-    activateTab (index) {
+    clickTab (index) {
       return (e) => {
         e.preventDefault()
-        if (typeof this.onSwitch === 'function') {
-          this.onSwitch.call(null, this.$slots.default[index].key)
-        }
-        this.active = index
-        if (this.scrollableTabs) {
-          this.$refs.contents.scrollTop = 0
-        }
+        this.setTab(index)
+      }
+    },
+    setTab (index) {
+      if (typeof this.onSwitch === 'function') {
+        this.onSwitch.call(null, this.$slots.default[index].key)
+      }
+      this.active = index
+      if (this.scrollableTabs) {
+        this.$refs.contents.scrollTop = 0
       }
     }
   },
@@ -88,7 +91,7 @@ export default Vue.component('tab-switcher', {
             <div class={classesWrapper.join(' ')}>
               <button
                 disabled={slot.data.attrs.disabled}
-                onClick={this.activateTab(index)}
+                onClick={this.clickTab(index)}
                 class={classesTab.join(' ')}>
                 <img src={slot.data.attrs.image} title={slot.data.attrs['image-tooltip']}/>
                 {slot.data.attrs.label ? '' : slot.data.attrs.label}
@@ -100,7 +103,7 @@ export default Vue.component('tab-switcher', {
           <div class={classesWrapper.join(' ')}>
             <button
               disabled={slot.data.attrs.disabled}
-              onClick={this.activateTab(index)}
+              onClick={this.clickTab(index)}
               class={classesTab.join(' ')}
               type="button"
             >
diff --git a/src/i18n/de.json b/src/i18n/de.json
index 3014b870..6fe6ab2c 100644
--- a/src/i18n/de.json
+++ b/src/i18n/de.json
@@ -478,7 +478,6 @@
     "placeholder": "Dein Benutzername oder die zugehörige E-Mail-Adresse",
     "check_email": "Im E-Mail-Posteingang des angebenen Kontos müsste sich jetzt (oder zumindest in Kürze) die E-Mail mit dem Link zum Passwortzurücksetzen befinden.",
     "return_home": "Zurück zur Heimseite",
-    "not_found": "Benutzername/E-Mail-Adresse nicht gefunden. Vertippt?",
     "too_many_requests": "Kurze Pause. Zu viele Versuche. Bitte, später nochmal probieren.",
     "password_reset_disabled": "Passwortzurücksetzen deaktiviert. Bitte Administrator kontaktieren.",
     "password_reset_required": "Passwortzurücksetzen erforderlich.",
diff --git a/src/i18n/en.json b/src/i18n/en.json
index e05ac907..8540f551 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -774,7 +774,6 @@
     "placeholder": "Your email or username",
     "check_email": "Check your email for a link to reset your password.",
     "return_home": "Return to the home page",
-    "not_found": "We couldn't find that email or username.",
     "too_many_requests": "You have reached the limit of attempts, try again later.",
     "password_reset_disabled": "Password reset is disabled. Please contact your instance administrator.",
     "password_reset_required": "You must reset your password to log in.",
diff --git a/src/i18n/eo.json b/src/i18n/eo.json
index b66f557a..e73ac2f8 100644
--- a/src/i18n/eo.json
+++ b/src/i18n/eo.json
@@ -776,7 +776,6 @@
     "password_reset_required": "Vi devas restarigi vian pasvorton por saluti.",
     "password_reset_disabled": "Restarigado de pasvortoj estas malŝaltita. Bonvolu kontakti la administranton de via nodo.",
     "too_many_requests": "Vi atingis la limon de provoj, reprovu pli poste.",
-    "not_found": "Ni ne trovis tiun retpoŝtadreson aŭ uzantonomon.",
     "return_home": "Reiri al la hejmpaĝo",
     "check_email": "Kontrolu vian retpoŝton pro ligilo por restarigi vian pasvorton.",
     "placeholder": "Via retpoŝtadreso aŭ uzantonomo",
diff --git a/src/i18n/es.json b/src/i18n/es.json
index 3f313eb3..718d9040 100644
--- a/src/i18n/es.json
+++ b/src/i18n/es.json
@@ -13,7 +13,8 @@
     "scope_options": "Opciones del alcance de la visibilidad",
     "text_limit": "Límite de caracteres",
     "title": "Características",
-    "who_to_follow": "A quién seguir"
+    "who_to_follow": "A quién seguir",
+    "pleroma_chat_messages": "Chat de Pleroma"
   },
   "finder": {
     "error_fetching_user": "Error al buscar usuario",
@@ -31,7 +32,13 @@
     "disable": "Inhabilitar",
     "enable": "Habilitar",
     "confirm": "Confirmar",
-    "verify": "Verificar"
+    "verify": "Verificar",
+    "peek": "Ojear",
+    "close": "Cerrar",
+    "dismiss": "Descartar",
+    "retry": "Inténtalo de nuevo",
+    "error_retry": "Por favor, inténtalo de nuevo",
+    "loading": "Cargando…"
   },
   "image_cropper": {
     "crop_picture": "Recortar la foto",
@@ -41,7 +48,7 @@
   },
   "importer": {
     "submit": "Enviar",
-    "success": "Importado con éxito",
+    "success": "Importado con éxito.",
     "error": "Se ha producido un error al importar el archivo."
   },
   "login": {
@@ -77,21 +84,27 @@
     "dms": "Mensajes Directos",
     "public_tl": "Línea Temporal Pública",
     "timeline": "Línea Temporal",
-    "twkn": "Toda La Red Conocida",
+    "twkn": "Red Conocida",
     "user_search": "Búsqueda de Usuarios",
     "search": "Buscar",
     "who_to_follow": "A quién seguir",
-    "preferences": "Preferencias"
+    "preferences": "Preferencias",
+    "chats": "Chats",
+    "timelines": "Líneas de Tiempo",
+    "bookmarks": "Marcadores"
   },
   "notifications": {
-    "broken_favorite": "Estado desconocido, buscándolo...",
+    "broken_favorite": "Estado desconocido, buscándolo…",
     "favorited_you": "le gusta tu estado",
     "followed_you": "empezó a seguirte",
     "load_older": "Cargar notificaciones antiguas",
     "notifications": "Notificaciones",
     "read": "¡Leído!",
     "repeated_you": "repitió tu estado",
-    "no_more_notifications": "No hay más notificaciones"
+    "no_more_notifications": "No hay más notificaciones",
+    "reacted_with": "reaccionó con {0}",
+    "migrated_to": "migrado a",
+    "follow_request": "quiere seguirte"
   },
   "polls": {
     "add_poll": "Añadir encuesta",
@@ -114,7 +127,9 @@
     "search_emoji": "Buscar un emoji",
     "add_emoji": "Insertar un emoji",
     "custom": "Emojis personalizados",
-    "unicode": "Emojis unicode"
+    "unicode": "Emojis unicode",
+    "load_all": "Cargando todos los {emojiAmount} emoji",
+    "load_all_hint": "Cargado el primer emoji {saneAmount}, cargar todos los emoji puede causar problemas de rendimiento."
   },
   "stickers": {
     "add_sticker": "Añadir Pegatina"
@@ -122,7 +137,8 @@
   "interactions": {
     "favs_repeats": "Favoritos y Repetidos",
     "follows": "Nuevos seguidores",
-    "load_older": "Cargar interacciones más antiguas"
+    "load_older": "Cargar interacciones más antiguas",
+    "moves": "Usuario Migrado"
   },
   "post_status": {
     "new_status": "Publicar un nuevo estado",
@@ -142,7 +158,7 @@
     "posting": "Publicando",
     "scope_notice": {
       "public": "Esta publicación será visible para todo el mundo",
-      "private": "Esta publicación solo será visible para tus seguidores.",
+      "private": "Esta publicación solo será visible para tus seguidores",
       "unlisted": "Esta publicación no será visible en la Línea Temporal Pública ni en Toda La Red Conocida"
     },
     "scope": {
@@ -150,7 +166,12 @@
       "private": "Solo-seguidores - Solo tus seguidores leerán la publicación",
       "public": "Público - Entradas visibles en las Líneas Temporales Públicas",
       "unlisted": "Sin listar - Entradas no visibles en las Líneas Temporales Públicas"
-    }
+    },
+    "media_description_error": "Error al actualizar el archivo, inténtalo de nuevo",
+    "empty_status_error": "No se puede publicar un estado vacío y sin archivos adjuntos",
+    "preview_empty": "Vacío",
+    "preview": "Vista previa",
+    "media_description": "Descripción multimedia"
   },
   "registration": {
     "bio": "Biografía",
@@ -189,7 +210,7 @@
       "generate_new_recovery_codes": "Generar códigos de recuperación nuevos",
       "warning_of_generate_new_codes": "Cuando generas nuevos códigos de recuperación, los antiguos dejarán de funcionar.",
       "recovery_codes": "Códigos de recuperación.",
-      "waiting_a_recovery_codes": "Recibiendo códigos de respaldo",
+      "waiting_a_recovery_codes": "Recibiendo códigos de respaldo…",
       "recovery_codes_warning": "Anote los códigos o guárdelos en un lugar seguro, de lo contrario no los volverá a ver. Si pierde el acceso a su aplicación 2FA y los códigos de recuperación, su cuenta quedará bloqueada.",
       "authentication_methods": "Métodos de autentificación",
       "scan": {
@@ -232,7 +253,7 @@
     "default_vis": "Alcance de visibilidad por defecto",
     "delete_account": "Eliminar la cuenta",
     "discoverable": "Permitir la aparición de esta cuenta en los resultados de búsqueda y otros servicios",
-    "delete_account_description": "Eliminar para siempre la cuenta y todos los mensajes.",
+    "delete_account_description": "Eliminar para siempre los datos y desactivar la cuenta.",
     "pad_emoji": "Rellenar con espacios al agregar emojis desde el selector",
     "delete_account_error": "Hubo un error al eliminar tu cuenta. Si el fallo persiste, ponte en contacto con el administrador de tu instancia.",
     "delete_account_instructions": "Escribe tu contraseña para confirmar la eliminación de tu cuenta.",
@@ -253,7 +274,7 @@
     "max_thumbnails": "Cantidad máxima de miniaturas por publicación",
     "hide_isp": "Ocultar el panel específico de la instancia",
     "preload_images": "Precargar las imágenes",
-    "use_one_click_nsfw": "Abrir los adjuntos NSFW con un solo click.",
+    "use_one_click_nsfw": "Abrir los adjuntos NSFW con un solo click",
     "hide_post_stats": "Ocultar las estadísticas de las entradas (p.ej. el número de favoritos)",
     "hide_user_stats": "Ocultar las estadísticas del usuario (p.ej. el número de seguidores)",
     "hide_filtered_statuses": "Ocultar estados filtrados",
@@ -299,7 +320,7 @@
     "valid_until": "Válido hasta",
     "revoke_token": "Revocar",
     "panelRadius": "Paneles",
-    "pause_on_unfocused": "Parar la transmisión cuando no estés en foco.",
+    "pause_on_unfocused": "Parar la transmisión cuando no estés en foco",
     "presets": "Por defecto",
     "profile_background": "Fondo del Perfil",
     "profile_banner": "Cabecera del Perfil",
@@ -355,7 +376,24 @@
         "save_load_hint": "Las opciones \"Mantener\" conservan las opciones configuradas actualmente al seleccionar o cargar temas, también almacena dichas opciones al exportar un tema. Cuando se desactiven todas las casillas de verificación, el tema de exportación lo guardará todo.",
         "reset": "Reiniciar",
         "clear_all": "Limpiar todo",
-        "clear_opacity": "Limpiar opacidad"
+        "clear_opacity": "Limpiar opacidad",
+        "help": {
+          "snapshot_source_mismatch": "Conflicto de versiones: lo más probable es que el frontend se haya revertido y actualizado nuevamente, si cambió el tema con una versión anterior del frontend, lo más probable es que desee usar la versión anterior; de lo contrario, use la nueva versión.",
+          "migration_napshot_gone": "Por alguna razón, faltaba la instantánea, algunas cosas podrían verse diferentes de lo que recuerdas.",
+          "migration_snapshot_ok": "Solo para estar seguro, se cargó la instantánea del tema. Puede intentar cargar los datos del tema.",
+          "fe_downgraded": "Versión de PleromaFE revertida.",
+          "fe_upgraded": "El creador de temas de PleromaFE se actualizó después de la actualización de la versión.",
+          "snapshot_missing": "No había ninguna instantánea del tema en el archivo, por lo que podría verse diferente de lo previsto originalmente.",
+          "snapshot_present": "Se ha cargado una instantánea del tema, por lo que todos los valores se sobrescriben. De lo contrario, puede cargar el tema por completo.",
+          "older_version_imported": "El archivo que ha importado se creó en una versión anterior del frontend actual.",
+          "v2_imported": "El archivo que ha importado fue creado para un frontend más antiguo. Intentamos maximizar la compatibilidad, pero aún podría haber inconsistencias.",
+          "future_version_imported": "El archivo que ha importado se creó para una versión más reciente del frontend.",
+          "upgraded_from_v2": "PleromaFE se ha actualizado, el tema podría verse un poco diferente de lo que recuerdas."
+        },
+        "use_source": "Nueva versión",
+        "use_snapshot": "Versión antigua",
+        "keep_as_is": "Mantener como está",
+        "load_theme": "Cargar tema"
       },
       "common": {
         "color": "Color",
@@ -390,7 +428,26 @@
         "borders": "Bordes",
         "buttons": "Botones",
         "inputs": "Campos de entrada",
-        "faint_text": "Texto desvanecido"
+        "faint_text": "Texto desvanecido",
+        "alert_neutral": "Neutral",
+        "chat": {
+          "border": "Borde",
+          "outgoing": "Salientes",
+          "incoming": "Entrantes"
+        },
+        "tabs": "Pestañas",
+        "toggled": "Intercambiado",
+        "disabled": "Deshabilitado",
+        "selectedMenu": "Elemento del menú seleccionado",
+        "selectedPost": "Publicación seleccionada",
+        "pressed": "Presionado",
+        "highlight": "Elementos destacados",
+        "icons": "Iconos",
+        "poll": "Gráfico de la encuesta",
+        "underlay": "Subrayado",
+        "popover": "Sugerencias, menús, superposiciones",
+        "post": "Publicaciones/Biografías de Usuarios",
+        "alert_warning": "Precaución"
       },
       "radii": {
         "_tab_label": "Redondez"
@@ -423,7 +480,8 @@
           "buttonPressed": "Botón (presionado)",
           "buttonPressedHover": "Botón (presionado+encima)",
           "input": "Campo de entrada"
-        }
+        },
+        "hintV3": "Para las sombras, también puede usar la notación {0} para usar otro espacio de color."
       },
       "fonts": {
         "_tab_label": "Fuentes",
@@ -458,7 +516,42 @@
       "title": "Versión",
       "backend_version": "Versión del Backend",
       "frontend_version": "Versión del Frontend"
-    }
+    },
+    "notification_visibility_moves": "Usuario Migrado",
+    "greentext": "Texto verde (meme arrows)",
+    "notification_setting_hide_notification_contents": "Ocultar el remitente y el contenido de las notificaciones push",
+    "notification_setting_privacy": "Privacidad",
+    "notification_setting_block_from_strangers": "Bloquea las notificaciones de los usuarios que no sigues",
+    "notification_setting_filters": "Filtros",
+    "fun": "Divertido",
+    "type_domains_to_mute": "Buscar dominios para silenciar",
+    "useStreamingApiWarning": "(no recomendado, experimental, puede omitir publicaciones)",
+    "useStreamingApi": "Recibir entradas y notificaciones en tiempo real",
+    "user_mutes": "Usuarios",
+    "reset_profile_background": "Restablecer el fondo de pantalla",
+    "reset_background_confirm": "¿Estás seguro de restablecer el fondo de pantalla?",
+    "reset_banner_confirm": "¿Estás seguro de restablecer la imagen del banner?",
+    "reset_avatar_confirm": "¿Estás seguro de restablecer la imagen de avatar?",
+    "reset_profile_banner": "Restabler imagen del banner del perfil",
+    "reset_avatar": "Restablecer avatar",
+    "notification_visibility_emoji_reactions": "Reacciones",
+    "new_email": "Nuevo correo electrónico",
+    "profile_fields": {
+      "value": "Contenido",
+      "name": "Etiqueta",
+      "add_field": "Añadir un campo",
+      "label": "Metadatos del perfil"
+    },
+    "accent": "Acento",
+    "emoji_reactions_on_timeline": "Mostrar las reacciones de emoji en la línea de tiempo",
+    "domain_mutes": "Dominios",
+    "mutes_and_blocks": "Silenciado y Bloqueados",
+    "chatMessageRadius": "Mensaje de chat",
+    "changed_email": "¡Correo electrónico modificado correctamente!",
+    "change_email_error": "Ha ocurrido un error al intentar modificar tu correo electrónico.",
+    "change_email": "Modificar el correo electrónico",
+    "bot": "Esta cuenta es un bot",
+    "allow_following_move": "Permitir el seguimiento automático, cuando la cuenta que sigues se traslada a otra instancia"
   },
   "time": {
     "day": "{0} día",
@@ -504,7 +597,8 @@
     "show_new": "Mostrar lo nuevo",
     "up_to_date": "Actualizado",
     "no_more_statuses": "No hay más estados",
-    "no_statuses": "Sin estados"
+    "no_statuses": "Sin estados",
+    "reload": "Recargar"
   },
   "status": {
     "favorites": "Favoritos",
@@ -517,7 +611,17 @@
     "reply_to": "Respondiendo a",
     "replies_list": "Respuestas:",
     "mute_conversation": "Silenciar la conversación",
-    "unmute_conversation": "Mostrar la conversación"
+    "unmute_conversation": "Mostrar la conversación",
+    "hide_content": "Ocultar el contenido",
+    "show_content": "Mostrar el contenido",
+    "hide_full_subject": "Ocultar el tema completo",
+    "show_full_subject": "Mostrar el tema completo",
+    "thread_muted_and_words": ", contiene:",
+    "thread_muted": "Conversación silenciada",
+    "copy_link": "Copiar el enlace al estado",
+    "status_unavailable": "Estado no disponible",
+    "bookmark": "Marcar",
+    "unbookmark": "Desmarcar"
   },
   "user_card": {
     "approve": "Aprobar",
@@ -546,11 +650,11 @@
     "subscribe": "Suscribirse",
     "unsubscribe": "Desuscribirse",
     "unblock": "Desbloquear",
-    "unblock_progress": "Desbloqueando...",
-    "block_progress": "Bloqueando...",
-    "unmute": "Quitar silencio",
-    "unmute_progress": "Quitando silencio...",
-    "mute_progress": "Silenciando...",
+    "unblock_progress": "Desbloqueando…",
+    "block_progress": "Bloqueando…",
+    "unmute": "Dejar de silenciar",
+    "unmute_progress": "Quitando silencio…",
+    "mute_progress": "Silenciando…",
     "admin_menu": {
       "moderation": "Moderación",
       "grant_admin": "Conceder permisos de Administrador",
@@ -564,12 +668,16 @@
       "strip_media": "Eliminar archivos multimedia de las publicaciones",
       "force_unlisted": "Forzar que se publique en el modo -Sin Listar-",
       "sandbox": "Forzar que se publique solo para tus seguidores",
-      "disable_remote_subscription": "No permitir que usuarios de instancias remotas te siga.",
+      "disable_remote_subscription": "No permitir que usuarios de instancias remotas te siga",
       "disable_any_subscription": "No permitir que ningún usuario te siga",
       "quarantine": "No permitir publicaciones de usuarios de instancias remotas",
       "delete_user": "Eliminar usuario",
       "delete_user_confirmation": "¿Estás completamente seguro? Esta acción no se puede deshacer."
-    }
+    },
+    "show_repeats": "Mostrar repetidos",
+    "hide_repeats": "Ocultar repetidos",
+    "message": "Mensaje",
+    "hidden": "Oculto"
   },
   "user_profile": {
     "timeline_title": "Linea Temporal del Usuario",
@@ -594,7 +702,11 @@
     "repeat": "Repetir",
     "reply": "Contestar",
     "favorite": "Favorito",
-    "user_settings": "Ajustes de usuario"
+    "user_settings": "Ajustes de usuario",
+    "bookmark": "Marcador",
+    "reject_follow_request": "Rechazar la solicitud de seguimiento",
+    "accept_follow_request": "Aceptar la solicitud de seguimiento",
+    "add_reaction": "Añadir Reacción"
   },
   "upload": {
     "error": {
@@ -624,8 +736,78 @@
     "placeholder": "Su correo electrónico o nombre de usuario",
     "check_email": "Revise su correo electrónico para obtener un enlace para restablecer su contraseña.",
     "return_home": "Volver a la página de inicio",
-    "not_found": "No pudimos encontrar ese correo electrónico o nombre de usuario.",
     "too_many_requests": "Has alcanzado el límite de intentos, vuelve a intentarlo más tarde.",
-    "password_reset_disabled": "El restablecimiento de contraseñas está deshabilitado. Póngase en contacto con el administrador de su instancia."
+    "password_reset_disabled": "El restablecimiento de contraseñas está deshabilitado. Póngase en contacto con el administrador de su instancia.",
+    "password_reset_required_but_mailer_is_disabled": "Debes restablecer la contraseña, pero el restablecimiento de contraseñas está deshabilitado. Por favor contacta con el administrador de la instancia.",
+    "password_reset_required": "Debes restablecer la contraseña para iniciar sesión."
+  },
+  "errors": {
+    "storage_unavailable": "Pleroma no pudo acceder al almacenamiento del navegador. Su inicio de sesión o su configuración local no se guardarán y puede encontrar problemas inesperados. Intente habilitar las cookies."
+  },
+  "domain_mute_card": {
+    "unmute_progress": "Quitando silencio…",
+    "unmute": "Dejar de silenciar",
+    "mute_progress": "Silenciando…",
+    "mute": "Silenciar"
+  },
+  "about": {
+    "mrf": {
+      "simple": {
+        "accept_desc": "Esta instancia solo acepta mensajes de las siguientes instancias:",
+        "media_nsfw_desc": "Esta instancia obliga a que los archivos multimedia se establezcan como sensibles en las publicaciones de las siguientes instancias:",
+        "media_nsfw": "Forzar Multimedia Como Sensible",
+        "media_removal_desc": "Esta instancia elimina los archivos multimedia de las publicaciones de las siguientes instancias:",
+        "media_removal": "Eliminar Multimedia",
+        "quarantine": "Cuarentena",
+        "ftl_removal_desc": "Esta instancia elimina las siguientes instancias de la línea de tiempo \"Toda la red conocida\":",
+        "ftl_removal": "Eliminar de la línea de tiempo \"Toda La Red Conocida\"",
+        "quarantine_desc": "Esta instancia enviará solo publicaciones públicas a las siguientes instancias:",
+        "simple_policies": "Políticas sobre instancias específicas",
+        "reject_desc": "Esta instancia no aceptará mensajes de las siguientes instancias:",
+        "reject": "Rechazar",
+        "accept": "Aceptar"
+      },
+      "mrf_policies_desc": "Las políticas MRF manipulan la federación de esta instancia con el resto del fediverso. Las siguientes políticas están habilitadas:",
+      "mrf_policies": "Habilitar políticas MRF",
+      "keyword": {
+        "ftl_removal": "Eliminar de la línea de tiempo \"Toda La Red Conocida\"",
+        "keyword_policies": "Política de Palabras Clave",
+        "is_replaced_by": "→",
+        "replace": "Reemplazar",
+        "reject": "Rechazar"
+      },
+      "federation": "Federación"
+    },
+    "staff": "Equipo"
+  },
+  "shoutbox": {
+    "title": "Jaula de Grillos"
+  },
+  "remote_user_resolver": {
+    "remote_user_resolver": "Resolución de usuario remoto",
+    "error": "No encontrado.",
+    "searching_for": "Buscando"
+  },
+  "chats": {
+    "chats": "Chats",
+    "empty_chat_list_placeholder": "Aún no tienes ninguna conversación. ¡Inicia una nueva conversación!",
+    "error_sending_message": "Algo salió mal al enviar el mensaje.",
+    "error_loading_chat": "Algo salió mal al cargar el chat.",
+    "delete_confirm": "¿Realmente quieres borrar este mensaje?",
+    "more": "Más",
+    "empty_message_error": "No puedes publicar un mensaje vacío",
+    "new": "Nueva conversación",
+    "delete": "Borrar",
+    "message_user": "Mensaje de {nickname}",
+    "you": "Tú:"
+  },
+  "display_date": {
+    "today": "Hoy"
+  },
+  "file_type": {
+    "file": "Archivo",
+    "image": "Imagen",
+    "video": "Vídeo",
+    "audio": "Audio"
   }
 }
diff --git a/src/i18n/eu.json b/src/i18n/eu.json
index f04203f0..fdca6b95 100644
--- a/src/i18n/eu.json
+++ b/src/i18n/eu.json
@@ -232,7 +232,7 @@
     "default_vis": "Lehenetsitako ikusgaitasunak",
     "delete_account": "Ezabatu kontua",
     "discoverable": "Baimendu zure kontua kanpo bilaketa-emaitzetan eta bestelako zerbitzuetan agertzea",
-    "delete_account_description": "Betirako ezabatu zure kontua eta zure mezu guztiak",
+    "delete_account_description": "Betirako ezabatu zure datuak eta desaktibatu kontua.",
     "pad_emoji": "Zuriuneak gehitu emoji bat aukeratzen denean",
     "delete_account_error": "Arazo bat gertatu da zure kontua ezabatzerakoan. Arazoa jarraitu eskero, administratzailearekin harremanetan jarri.",
     "delete_account_instructions": "Idatzi zure pasahitza kontua ezabatzeko.",
@@ -626,10 +626,17 @@
     "placeholder": "Zure e-posta edo erabiltzaile izena",
     "check_email": "Begiratu zure posta elektronikoa pasahitza berrezarri ahal izateko.",
     "return_home": "Itzuli hasierara",
-    "not_found": "Ezin izan dugu helbide elektroniko edo erabiltzaile hori aurkitu.",
     "too_many_requests": "Saiakera gehiegi burutu ditzu, saiatu berriro geroxeago.",
     "password_reset_disabled": "Pasahitza berrezartzea debekatuta dago. Mesedez, jarri harremanetan instantzia administratzailearekin.",
     "password_reset_required": "Pasahitza berrezarri behar duzu saioa hasteko.",
     "password_reset_required_but_mailer_is_disabled": "Pasahitza berrezarri behar duzu, baina pasahitza berrezartzeko aukera desgaituta dago. Mesedez, jarri harremanetan instantziaren administratzailearekin."
+  },
+  "about": {
+    "mrf": {
+      "keyword": {
+        "keyword_policies": "Gako-hitz politika"
+      },
+      "federation": "Federazioa"
+    }
   }
 }
diff --git a/src/i18n/fi.json b/src/i18n/fi.json
index 510b2234..3832dcaa 100644
--- a/src/i18n/fi.json
+++ b/src/i18n/fi.json
@@ -752,7 +752,6 @@
     "password_reset": "Salasanan nollaus",
     "placeholder": "Sähköpostiosoite tai käyttäjänimi",
     "return_home": "Palaa etusivulle",
-    "not_found": "Sähköpostiosoitetta tai käyttäjänimeä ei löytynyt.",
     "too_many_requests": "Olet käyttänyt kaikki yritykset, yritä uudelleen myöhemmin.",
     "password_reset_required": "Sinun täytyy vaihtaa salasana kirjautuaksesi."
   },
diff --git a/src/i18n/fr.json b/src/i18n/fr.json
index 794ed812..3b7eefaf 100644
--- a/src/i18n/fr.json
+++ b/src/i18n/fr.json
@@ -730,7 +730,6 @@
     "instruction": "Entrer votre address de courriel ou votre nom utilisateur. Nous enverrons un lien pour changer votre mot de passe.",
     "placeholder": "Votre email ou nom d'utilisateur",
     "return_home": "Retourner à la page d'accueil",
-    "not_found": "Email ou nom d'utilisateur inconnu.",
     "too_many_requests": "Vos avez atteint la limite d'essais, essayez plus tard.",
     "password_reset_required": "Vous devez changer votre mot de passe pour vous authentifier."
   }
diff --git a/src/i18n/it.json b/src/i18n/it.json
index b88fdd29..474e7fde 100644
--- a/src/i18n/it.json
+++ b/src/i18n/it.json
@@ -745,7 +745,6 @@
     "password_reset_required": "Devi reimpostare la tua password per poter continuare.",
     "password_reset_disabled": "Non puoi azzerare la tua password. Contatta il tuo amministratore.",
     "too_many_requests": "Hai raggiunto il numero massimo di tentativi, riprova più tardi.",
-    "not_found": "Non ho trovato questa email o nome utente.",
     "return_home": "Torna alla pagina principale",
     "check_email": "Controlla la tua posta elettronica.",
     "placeholder": "La tua email o nome utente",
diff --git a/src/i18n/ja_easy.json b/src/i18n/ja_easy.json
index 255648e7..991f3762 100644
--- a/src/i18n/ja_easy.json
+++ b/src/i18n/ja_easy.json
@@ -666,7 +666,6 @@
     "placeholder": "あなたのメールアドレスかユーザーめい",
     "check_email": "パスワードをリセットするためのリンクがかかれたメールが、とどいているかどうか、みてください。",
     "return_home": "ホームページにもどる",
-    "not_found": "そのメールアドレスまたはユーザーめいを、みつけることができませんでした。",
     "too_many_requests": "パスワードリセットを、ためすことが、おおすぎます。しばらくしてから、ためしてください。",
     "password_reset_disabled": "このインスタンスでは、パスワードリセットは、できません。インスタンスのアドミニストレーターに、おといあわせください。",
     "password_reset_required": "ログインするには、パスワードをリセットしてください。",
diff --git a/src/i18n/ja_pedantic.json b/src/i18n/ja_pedantic.json
index 07fea45d..e2de1066 100644
--- a/src/i18n/ja_pedantic.json
+++ b/src/i18n/ja_pedantic.json
@@ -625,7 +625,6 @@
     "placeholder": "メールアドレスまたはユーザー名",
     "check_email": "パスワードをリセットするためのリンクが記載されたメールが届いているか確認してください。",
     "return_home": "ホームページに戻る",
-    "not_found": "メールアドレスまたはユーザー名が見つかりませんでした。",
     "too_many_requests": "試行回数の制限に達しました。しばらく時間を置いてから再試行してください。",
     "password_reset_disabled": "このインスタンスではパスワードリセットは無効になっています。インスタンスの管理者に連絡してください。"
   }
diff --git a/src/i18n/nl.json b/src/i18n/nl.json
index e7509f12..a01e57a0 100644
--- a/src/i18n/nl.json
+++ b/src/i18n/nl.json
@@ -677,7 +677,6 @@
     "password_reset_required": "Je dient je wachtwoord opnieuw in te stellen om in te kunnen loggen.",
     "password_reset_disabled": "Wachtwoord reset is uitgeschakeld. Neem contact op met de beheerder van deze instantie.",
     "too_many_requests": "Je hebt het maximaal aantal pogingen bereikt, probeer het later opnieuw.",
-    "not_found": "We kunnen die email of gebruikersnaam niet vinden.",
     "return_home": "Terugkeren naar de home pagina",
     "check_email": "Controleer je email inbox voor een link om je wachtwoord opnieuw in te stellen.",
     "placeholder": "Je email of gebruikersnaam",
diff --git a/src/i18n/pl.json b/src/i18n/pl.json
index 5863ba8e..05a7edf7 100644
--- a/src/i18n/pl.json
+++ b/src/i18n/pl.json
@@ -753,7 +753,6 @@
     "placeholder": "Twój email lub nazwa użytkownika",
     "check_email": "Sprawdź pocztę, aby uzyskać link do zresetowania hasła.",
     "return_home": "Wróć do strony głównej",
-    "not_found": "Nie mogliśmy znaleźć tego emaila lub nazwy użytkownika.",
     "too_many_requests": "Przekroczyłeś(-aś) limit prób, spróbuj ponownie później.",
     "password_reset_disabled": "Resetowanie hasła jest wyłączone. Proszę skontaktuj się z administratorem tej instancji.",
     "password_reset_required": "Musisz zresetować hasło, by się zalogować.",
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index df172935..3444a26d 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -420,7 +420,6 @@
     "placeholder": "Ваш email или имя пользователя",
     "check_email": "Проверьте ваш email и перейдите по ссылке для сброса пароля.",
     "return_home": "Вернуться на главную страницу",
-    "not_found": "Мы не смогли найти аккаунт с таким email-ом или именем пользователя.",
     "too_many_requests": "Вы исчерпали допустимое количество попыток, попробуйте позже.",
     "password_reset_disabled": "Сброс пароля отключен. Cвяжитесь с администратором вашего сервера."
   },
diff --git a/src/i18n/zh.json b/src/i18n/zh.json
index 24b799df..8c693f4d 100644
--- a/src/i18n/zh.json
+++ b/src/i18n/zh.json
@@ -640,7 +640,6 @@
     "placeholder": "你的电邮地址或者用户名",
     "check_email": "检查你的邮箱,会有一个链接用于重置密码。",
     "return_home": "回到首页",
-    "not_found": "我们无法找到匹配的邮箱地址或者用户名。",
     "too_many_requests": "你触发了尝试的限制,请稍后再试。",
     "password_reset_disabled": "密码重置已经被禁用。请联系你的实例管理员。"
   },
diff --git a/src/modules/interface.js b/src/modules/interface.js
index 748d3025..d6db32fd 100644
--- a/src/modules/interface.js
+++ b/src/modules/interface.js
@@ -3,6 +3,7 @@ import { set, delete as del } from 'vue'
 const defaultState = {
   settingsModalState: 'hidden',
   settingsModalLoaded: false,
+  settingsModalTargetTab: null,
   settings: {
     currentSaveStateNotice: null,
     noticeClearTimeout: null,
@@ -62,6 +63,9 @@ const interfaceMod = {
         state.settingsModalLoaded = true
       }
     },
+    setSettingsModalTargetTab (state, value) {
+      state.settingsModalTargetTab = value
+    },
     pushGlobalNotice (state, notice) {
       state.globalNotices.push(notice)
     },
@@ -97,6 +101,13 @@ const interfaceMod = {
     togglePeekSettingsModal ({ commit }) {
       commit('togglePeekSettingsModal')
     },
+    clearSettingsModalTargetTab ({ commit }) {
+      commit('setSettingsModalTargetTab', null)
+    },
+    openSettingsModalTab ({ commit }, value) {
+      commit('setSettingsModalTargetTab', value)
+      commit('openSettingsModal')
+    },
     pushGlobalNotice (
       { commit, dispatch },
       {
diff --git a/src/services/chat_utils/chat_utils.js b/src/services/chat_utils/chat_utils.js
index ab898ced..583438f7 100644
--- a/src/services/chat_utils/chat_utils.js
+++ b/src/services/chat_utils/chat_utils.js
@@ -3,6 +3,7 @@ import { showDesktopNotification } from '../desktop_notification_utils/desktop_n
 export const maybeShowChatNotification = (store, chat) => {
   if (!chat.lastMessage) return
   if (store.rootState.chats.currentChatId === chat.id && !document.hidden) return
+  if (store.rootState.users.currentUser.id === chat.lastMessage.account.id) return
 
   const opts = {
     tag: chat.lastMessage.id,
diff --git a/src/services/completion/completion.js b/src/services/completion/completion.js
index df83d03d..8a6eba7e 100644
--- a/src/services/completion/completion.js
+++ b/src/services/completion/completion.js
@@ -5,7 +5,7 @@ export const replaceWord = (str, toReplace, replacement) => {
 }
 
 export const wordAtPosition = (str, pos) => {
-  const words = splitIntoWords(str)
+  const words = splitByWhitespaceBoundary(str)
   const wordsWithPosition = addPositionToWords(words)
 
   return find(wordsWithPosition, ({ start, end }) => start <= pos && end > pos)
@@ -34,36 +34,36 @@ export const addPositionToWords = (words) => {
   }, [])
 }
 
-export const splitIntoWords = (str) => {
-  // Split at word boundaries
-  const regex = /\b/
-  const triggers = /[@#:]+$/
-
-  let split = str.split(regex)
-
-  // Add trailing @ and # to the following word.
-  const words = reduce(split, (result, word) => {
-    if (result.length > 0) {
-      let previous = result.pop()
-      const matches = previous.match(triggers)
-      if (matches) {
-        previous = previous.replace(triggers, '')
-        word = matches[0] + word
-      }
-      result.push(previous)
+export const splitByWhitespaceBoundary = (str) => {
+  let result = []
+  let currentWord = ''
+  for (let i = 0; i < str.length; i++) {
+    const currentChar = str[i]
+    // Starting a new word
+    if (!currentWord) {
+      currentWord = currentChar
+      continue
     }
-    result.push(word)
-
-    return result
-  }, [])
-
-  return words
+    // current character is whitespace while word isn't, or vice versa:
+    // add our current word to results, start over the current word.
+    if (!!currentChar.trim() !== !!currentWord.trim()) {
+      result.push(currentWord)
+      currentWord = currentChar
+      continue
+    }
+    currentWord += currentChar
+  }
+  // Add the last word we were working on
+  if (currentWord) {
+    result.push(currentWord)
+  }
+  return result
 }
 
 const completion = {
   wordAtPosition,
   addPositionToWords,
-  splitIntoWords,
+  splitByWhitespaceBoundary,
   replaceWord
 }
 
diff --git a/test/unit/specs/services/completion/completion.spec.js b/test/unit/specs/services/completion/completion.spec.js
index 8a41c653..81d3a26a 100644
--- a/test/unit/specs/services/completion/completion.spec.js
+++ b/test/unit/specs/services/completion/completion.spec.js
@@ -1,8 +1,8 @@
-import { replaceWord, addPositionToWords, wordAtPosition, splitIntoWords } from '../../../../../src/services/completion/completion.js'
+import { replaceWord, addPositionToWords, wordAtPosition, splitByWhitespaceBoundary } from '../../../../../src/services/completion/completion.js'
 
 describe('addPositiontoWords', () => {
   it('adds the position to a word list', () => {
-    const words = ['hey', 'this', 'is', 'fun']
+    const words = ['hey', ' ', 'this', ' ', 'is', ' ', 'fun']
 
     const expected = [
       {
@@ -11,19 +11,34 @@ describe('addPositiontoWords', () => {
         end: 3
       },
       {
-        word: 'this',
+        word: ' ',
         start: 3,
-        end: 7
+        end: 4
       },
       {
-        word: 'is',
-        start: 7,
+        word: 'this',
+        start: 4,
+        end: 8
+      },
+      {
+        word: ' ',
+        start: 8,
         end: 9
       },
       {
-        word: 'fun',
+        word: 'is',
         start: 9,
+        end: 11
+      },
+      {
+        word: ' ',
+        start: 11,
         end: 12
+      },
+      {
+        word: 'fun',
+        start: 12,
+        end: 15
       }
     ]
 
@@ -33,11 +48,11 @@ describe('addPositiontoWords', () => {
   })
 })
 
-describe('splitIntoWords', () => {
+describe('splitByWhitespaceBoundary', () => {
   it('splits at whitespace boundaries', () => {
-    const str = 'This is a #nice @test for you, @idiot.'
-    const expected = ['This', ' ', 'is', ' ', 'a', ' ', '#nice', ' ', '@test', ' ', 'for', ' ', 'you', ', ', '@idiot', '.']
-    const res = splitIntoWords(str)
+    const str = 'This is a #nice @test for you,    @idiot@idiot.com'
+    const expected = ['This', ' ', 'is', ' ', 'a', ' ', '#nice', ' ', '@test', ' ', 'for', ' ', 'you,', '    ', '@idiot@idiot.com']
+    const res = splitByWhitespaceBoundary(str)
 
     expect(res).to.eql(expected)
   })
@@ -57,13 +72,13 @@ describe('wordAtPosition', () => {
 
 describe('replaceWord', () => {
   it('replaces a word (with start and end) with another word in a given string', () => {
-    const str = 'hey @take, how are you'
-    const wordsWithPosition = addPositionToWords(splitIntoWords(str))
+    const str = 'hey @take , how are you'
+    const wordsWithPosition = addPositionToWords(splitByWhitespaceBoundary(str))
     const toReplace = wordsWithPosition[2]
 
     expect(toReplace.word).to.eql('@take')
 
-    const expected = 'hey @takeshitakenji, how are you'
+    const expected = 'hey @takeshitakenji , how are you'
     const res = replaceWord(str, toReplace, '@takeshitakenji')
     expect(res).to.eql(expected)
   })