about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorDavid Yip <yipdw@member.fsf.org>2018-03-12 17:52:19 -0500
committerDavid Yip <yipdw@member.fsf.org>2018-03-12 17:52:19 -0500
commitf8e934f95551179de48a716d4f148bb7bec638d1 (patch)
tree79ca73d8d3346dc5ee5a38bce919e43e3c4e99bd /app
parent22f2750578c64af4e886b0cc704aa0be4ee209b0 (diff)
parent051b649628d8039ff15f0c035c6f8fe5dbf045d6 (diff)
Merge remote-tracking branch 'origin/master' into merge-upstream
 Conflicts:
	README.md
Diffstat (limited to 'app')
-rw-r--r--app/javascript/mastodon/actions/notifications.js2
-rw-r--r--app/javascript/mastodon/components/media_gallery.js65
-rw-r--r--app/javascript/mastodon/features/account_timeline/index.js10
-rw-r--r--app/javascript/mastodon/features/compose/containers/warning_container.js2
-rw-r--r--app/javascript/mastodon/features/ui/components/focal_point_modal.js2
-rw-r--r--app/javascript/mastodon/features/ui/components/media_modal.js35
-rw-r--r--app/javascript/mastodon/locales/ar.json4
-rw-r--r--app/javascript/mastodon/locales/bg.json2
-rw-r--r--app/javascript/mastodon/locales/ca.json2
-rw-r--r--app/javascript/mastodon/locales/de.json2
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json8
-rw-r--r--app/javascript/mastodon/locales/en.json2
-rw-r--r--app/javascript/mastodon/locales/eo.json2
-rw-r--r--app/javascript/mastodon/locales/es.json2
-rw-r--r--app/javascript/mastodon/locales/fa.json2
-rw-r--r--app/javascript/mastodon/locales/fi.json26
-rw-r--r--app/javascript/mastodon/locales/fr.json2
-rw-r--r--app/javascript/mastodon/locales/gl.json2
-rw-r--r--app/javascript/mastodon/locales/he.json2
-rw-r--r--app/javascript/mastodon/locales/hr.json2
-rw-r--r--app/javascript/mastodon/locales/hu.json2
-rw-r--r--app/javascript/mastodon/locales/hy.json2
-rw-r--r--app/javascript/mastodon/locales/id.json2
-rw-r--r--app/javascript/mastodon/locales/io.json2
-rw-r--r--app/javascript/mastodon/locales/it.json2
-rw-r--r--app/javascript/mastodon/locales/ja.json4
-rw-r--r--app/javascript/mastodon/locales/ko.json2
-rw-r--r--app/javascript/mastodon/locales/nl.json2
-rw-r--r--app/javascript/mastodon/locales/no.json2
-rw-r--r--app/javascript/mastodon/locales/oc.json2
-rw-r--r--app/javascript/mastodon/locales/pl.json6
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json2
-rw-r--r--app/javascript/mastodon/locales/pt.json2
-rw-r--r--app/javascript/mastodon/locales/ru.json2
-rw-r--r--app/javascript/mastodon/locales/sk.json6
-rw-r--r--app/javascript/mastodon/locales/sr-Latn.json2
-rw-r--r--app/javascript/mastodon/locales/sr.json2
-rw-r--r--app/javascript/mastodon/locales/sv.json24
-rw-r--r--app/javascript/mastodon/locales/th.json2
-rw-r--r--app/javascript/mastodon/locales/tr.json2
-rw-r--r--app/javascript/mastodon/locales/uk.json2
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json2
-rw-r--r--app/javascript/mastodon/locales/zh-HK.json2
-rw-r--r--app/javascript/mastodon/locales/zh-TW.json2
-rw-r--r--app/javascript/mastodon/reducers/compose.js14
-rw-r--r--app/javascript/styles/mastodon/components.scss31
-rw-r--r--app/models/tag.rb2
47 files changed, 177 insertions, 126 deletions
diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js
index 502690045..cf9242d0f 100644
--- a/app/javascript/mastodon/actions/notifications.js
+++ b/app/javascript/mastodon/actions/notifications.js
@@ -24,7 +24,7 @@ defineMessages({
 const fetchRelatedRelationships = (dispatch, notifications) => {
   const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id);
 
-  if (accountIds > 0) {
+  if (accountIds.length > 0) {
     dispatch(fetchRelationships(accountIds));
   }
 };
diff --git a/app/javascript/mastodon/components/media_gallery.js b/app/javascript/mastodon/components/media_gallery.js
index 9310e7c96..1cef029d8 100644
--- a/app/javascript/mastodon/components/media_gallery.js
+++ b/app/javascript/mastodon/components/media_gallery.js
@@ -12,26 +12,6 @@ const messages = defineMessages({
   toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },
 });
 
-const shiftToPoint = (containerToImageRatio, containerSize, imageSize, focusSize, toMinus) => {
-  const containerCenter = Math.floor(containerSize / 2);
-  const focusFactor     = (focusSize + 1) / 2;
-  const scaledImage     = Math.floor(imageSize / containerToImageRatio);
-
-  let focus = Math.floor(focusFactor * scaledImage);
-
-  if (toMinus) focus = scaledImage - focus;
-
-  let focusOffset = focus - containerCenter;
-
-  const remainder = scaledImage - focus;
-  const containerRemainder = containerSize - containerCenter;
-
-  if (remainder < containerRemainder) focusOffset -= containerRemainder - remainder;
-  if (focusOffset < 0) focusOffset = 0;
-
-  return (focusOffset * -100 / containerSize) + '%';
-};
-
 class Item extends React.PureComponent {
 
   static contextTypes = {
@@ -44,8 +24,6 @@ class Item extends React.PureComponent {
     index: PropTypes.number.isRequired,
     size: PropTypes.number.isRequired,
     onClick: PropTypes.func.isRequired,
-    containerWidth: PropTypes.number,
-    containerHeight: PropTypes.number,
   };
 
   static defaultProps = {
@@ -84,7 +62,7 @@ class Item extends React.PureComponent {
   }
 
   render () {
-    const { attachment, index, size, standalone, containerWidth, containerHeight } = this.props;
+    const { attachment, index, size, standalone } = this.props;
 
     let width  = 50;
     let height = 100;
@@ -143,45 +121,16 @@ class Item extends React.PureComponent {
 
       const originalUrl    = attachment.get('url');
       const originalWidth  = attachment.getIn(['meta', 'original', 'width']);
-      const originalHeight = attachment.getIn(['meta', 'original', 'height']);
 
       const hasSize = typeof originalWidth === 'number' && typeof previewWidth === 'number';
 
       const srcSet = hasSize ? `${originalUrl} ${originalWidth}w, ${previewUrl} ${previewWidth}w` : null;
       const sizes  = hasSize ? `(min-width: 1025px) ${320 * (width / 100)}px, ${width}vw` : null;
 
-      const focusX     = attachment.getIn(['meta', 'focus', 'x']);
-      const focusY     = attachment.getIn(['meta', 'focus', 'y']);
-      const imageStyle = {};
-
-      if (originalWidth && originalHeight && containerWidth && containerHeight && focusX && focusY) {
-        const widthRatio  = originalWidth / (containerWidth * (width / 100));
-        const heightRatio = originalHeight / (containerHeight * (height / 100));
-
-        let hShift = 0;
-        let vShift = 0;
-
-        if (widthRatio > heightRatio) {
-          hShift = shiftToPoint(heightRatio, (containerWidth * (width / 100)), originalWidth, focusX);
-        } else if(widthRatio < heightRatio) {
-          vShift = shiftToPoint(widthRatio, (containerHeight * (height / 100)), originalHeight, focusY, true);
-        }
-
-        if (originalWidth > originalHeight) {
-          imageStyle.height   = '100%';
-          imageStyle.width    = 'auto';
-          imageStyle.minWidth = '100%';
-        } else {
-          imageStyle.height    = 'auto';
-          imageStyle.width     = '100%';
-          imageStyle.minHeight = '100%';
-        }
-
-        imageStyle.top  = vShift;
-        imageStyle.left = hShift;
-      } else {
-        imageStyle.height = '100%';
-      }
+      const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
+      const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;
+      const x      = ((focusX /  2) + .5) * 100;
+      const y      = ((focusY / -2) + .5) * 100;
 
       thumbnail = (
         <a
@@ -196,7 +145,7 @@ class Item extends React.PureComponent {
             sizes={sizes}
             alt={attachment.get('description')}
             title={attachment.get('description')}
-            style={imageStyle}
+            style={{ objectPosition: `${x}% ${y}%` }}
           />
         </a>
       );
@@ -320,7 +269,7 @@ export default class MediaGallery extends React.PureComponent {
       if (this.isStandaloneEligible()) {
         children = <Item standalone onClick={this.handleClick} attachment={media.get(0)} />;
       } else {
-        children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} containerWidth={width} containerHeight={style.height} />);
+        children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} index={i} size={size} />);
       }
     }
 
diff --git a/app/javascript/mastodon/features/account_timeline/index.js b/app/javascript/mastodon/features/account_timeline/index.js
index f5f2475ea..5e21cf7c6 100644
--- a/app/javascript/mastodon/features/account_timeline/index.js
+++ b/app/javascript/mastodon/features/account_timeline/index.js
@@ -17,7 +17,7 @@ const mapStateToProps = (state, { params: { accountId }, withReplies = false })
 
   return {
     statusIds: state.getIn(['timelines', `account:${path}`, 'items'], ImmutableList()),
-    featuredStatusIds: state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()),
+    featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()),
     isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
     hasMore: !!state.getIn(['timelines', `account:${path}`, 'next']),
   };
@@ -40,14 +40,18 @@ export default class AccountTimeline extends ImmutablePureComponent {
     const { params: { accountId }, withReplies } = this.props;
 
     this.props.dispatch(fetchAccount(accountId));
-    this.props.dispatch(refreshAccountFeaturedTimeline(accountId));
+    if (!withReplies) {
+      this.props.dispatch(refreshAccountFeaturedTimeline(accountId));
+    }
     this.props.dispatch(refreshAccountTimeline(accountId, withReplies));
   }
 
   componentWillReceiveProps (nextProps) {
     if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
       this.props.dispatch(fetchAccount(nextProps.params.accountId));
-      this.props.dispatch(refreshAccountFeaturedTimeline(nextProps.params.accountId));
+      if (!nextProps.withReplies) {
+        this.props.dispatch(refreshAccountFeaturedTimeline(nextProps.params.accountId));
+      }
       this.props.dispatch(refreshAccountTimeline(nextProps.params.accountId, nextProps.params.withReplies));
     }
   }
diff --git a/app/javascript/mastodon/features/compose/containers/warning_container.js b/app/javascript/mastodon/features/compose/containers/warning_container.js
index dbb80dfb0..8ee8ea190 100644
--- a/app/javascript/mastodon/features/compose/containers/warning_container.js
+++ b/app/javascript/mastodon/features/compose/containers/warning_container.js
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
 import { me } from '../../../initial_state';
 
-const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\w*[a-zA-Z]\w*)/i;
+const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\w*[a-zA-Z·]\w*)/i;
 
 const mapStateToProps = state => ({
   needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),
diff --git a/app/javascript/mastodon/features/ui/components/focal_point_modal.js b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
index 1038e1864..21bf6d81b 100644
--- a/app/javascript/mastodon/features/ui/components/focal_point_modal.js
+++ b/app/javascript/mastodon/features/ui/components/focal_point_modal.js
@@ -103,7 +103,7 @@ export default class FocalPointModal extends ImmutablePureComponent {
     const height = media.getIn(['meta', 'original', 'height']) || null;
 
     return (
-      <div className='modal-root__modal video-modal'>
+      <div className='modal-root__modal video-modal focal-point-modal'>
         <div className={classNames('focal-point', { dragging })} ref={this.setRef}>
           <ImageLoader
             previewSrc={media.get('preview_url')}
diff --git a/app/javascript/mastodon/features/ui/components/media_modal.js b/app/javascript/mastodon/features/ui/components/media_modal.js
index 72ef32256..fb76270fa 100644
--- a/app/javascript/mastodon/features/ui/components/media_modal.js
+++ b/app/javascript/mastodon/features/ui/components/media_modal.js
@@ -130,6 +130,15 @@ export default class MediaModal extends ImmutablePureComponent {
       return null;
     }).toArray();
 
+    // you can't use 100vh, because the viewport height is taller
+    // than the visible part of the document in some mobile
+    // browsers when it's address bar is visible.
+    // https://developers.google.com/web/updates/2016/12/url-bar-resizing
+    const swipeableViewsStyle = {
+      width: '100%',
+      height: '100%',
+    };
+
     const containerStyle = {
       alignItems: 'center', // center vertically
     };
@@ -145,23 +154,15 @@ export default class MediaModal extends ImmutablePureComponent {
           role='presentation'
           onClick={onClose}
         >
-          <div className='media-modal__content'>
-            <ReactSwipeableViews
-              style={{
-                // you can't use 100vh, because the viewport height is taller
-                // than the visible part of the document in some mobile
-                // browsers when it's address bar is visible.
-                // https://developers.google.com/web/updates/2016/12/url-bar-resizing
-                height: `${document.body.clientHeight}px`,
-              }}
-              containerStyle={containerStyle}
-              onChangeIndex={this.handleSwipe}
-              onSwitching={this.handleSwitching}
-              index={index}
-            >
-              {content}
-            </ReactSwipeableViews>
-          </div>
+          <ReactSwipeableViews
+            style={swipeableViewsStyle}
+            containerStyle={containerStyle}
+            onChangeIndex={this.handleSwipe}
+            onSwitching={this.handleSwitching}
+            index={index}
+          >
+            {content}
+          </ReactSwipeableViews>
         </div>
         <div className={navigationClassName}>
           <IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={40} />
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index 33e223b2a..397927abb 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -3,7 +3,7 @@
   "account.block_domain": "إخفاء كل شيئ قادم من إسم النطاق {domain}",
   "account.blocked": "محظور",
   "account.disclaimer_full": "قد لا تعكس المعلومات أدناه الملف الشخصي الكامل للمستخدم.",
-  "account.domain_blocked": "Domain hidden",
+  "account.domain_blocked": "النطاق مخفي",
   "account.edit_profile": "تعديل الملف الشخصي",
   "account.follow": "تابِع",
   "account.followers": "المتابعون",
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "محتوى حساس",
   "status.share": "مشاركة",
   "status.show_less": "إعرض أقلّ",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "أظهر المزيد",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "فك الكتم عن المحادثة",
   "status.unpin": "فك التدبيس من الملف الشخصي",
   "tabs_bar.federated_timeline": "الموحَّد",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index a84e6e9d1..673ce0bc3 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Деликатно съдържание",
   "status.share": "Share",
   "status.show_less": "Show less",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Show more",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Unmute conversation",
   "status.unpin": "Unpin from profile",
   "tabs_bar.federated_timeline": "Federated",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index bac807dbb..318b36c96 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Contingut sensible",
   "status.share": "Compartir",
   "status.show_less": "Mostra menys",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Mostra més",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Activar conversació",
   "status.unpin": "Deslliga del perfil",
   "tabs_bar.federated_timeline": "Federada",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index 6267b1d71..92dc51be0 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Heikle Inhalte",
   "status.share": "Teilen",
   "status.show_less": "Weniger anzeigen",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Mehr anzeigen",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Stummschaltung von Thread aufheben",
   "status.unpin": "Vom Profil lösen",
   "tabs_bar.federated_timeline": "Föderation",
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index c8ebf4b87..54ebc7dd7 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -1376,6 +1376,14 @@
         "id": "confirmations.block.confirm"
       },
       {
+        "defaultMessage": "Show more for all",
+        "id": "status.show_more_all"
+      },
+      {
+        "defaultMessage": "Show less for all",
+        "id": "status.show_less_all"
+      },
+      {
         "defaultMessage": "Are you sure you want to block {name}?",
         "id": "confirmations.block.message"
       }
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index e6e0b012b..5efc85f6c 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -259,7 +259,9 @@
   "status.sensitive_warning": "Sensitive content",
   "status.share": "Share",
   "status.show_less": "Show less",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Show more",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Unmute conversation",
   "status.unpin": "Unpin from profile",
   "tabs_bar.federated_timeline": "Federated",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index 4f465bf40..03719963f 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Tikla enhavo",
   "status.share": "Diskonigi",
   "status.show_less": "Malgrandigi",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Grandigi",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Malsilentigi konversacion",
   "status.unpin": "Depingli de profilo",
   "tabs_bar.federated_timeline": "Fratara tempolinio",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index d172dff1c..8ecb81ddf 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Contenido sensible",
   "status.share": "Compartir",
   "status.show_less": "Mostrar menos",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Mostrar más",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Dejar de silenciar conversación",
   "status.unpin": "Dejar de fijar",
   "tabs_bar.federated_timeline": "Federado",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index b5b81bff9..50aa12a05 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "محتوای حساس",
   "status.share": "هم‌رسانی",
   "status.show_less": "نهفتن",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "نمایش",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "باصداکردن گفتگو",
   "status.unpin": "برداشتن نوشتهٔ ثابت نمایه",
   "tabs_bar.federated_timeline": "همگانی",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index aa97aae84..f4d730c0c 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -1,7 +1,7 @@
 {
   "account.block": "Estä @{name}",
   "account.block_domain": "Piilota kaikki sisältö verkkotunnuksesta {domain}",
-  "account.blocked": "Blocked",
+  "account.blocked": "Estetty",
   "account.disclaimer_full": "Alla olevat käyttäjän profiilitiedot saattavat olla epätäydellisiä.",
   "account.domain_blocked": "Domain hidden",
   "account.edit_profile": "Muokkaa",
@@ -15,9 +15,9 @@
   "account.moved_to": "{name} on muuttanut instanssiin:",
   "account.mute": "Mykistä @{name}",
   "account.mute_notifications": "Mykistä ilmoitukset käyttäjältä @{name}",
-  "account.muted": "Muted",
+  "account.muted": "Mykistetty",
   "account.posts": "Töötit",
-  "account.posts_with_replies": "Toots with replies",
+  "account.posts_with_replies": "Töötit ja vastaukset",
   "account.report": "Report @{name}",
   "account.requested": "Odottaa hyväksyntää. Klikkaa peruuttaaksesi seurauspyynnön",
   "account.share": "Jaa käyttäjän @{name} profiili",
@@ -211,22 +211,22 @@
   "relative_time.minutes": "{number}m",
   "relative_time.seconds": "{number}s",
   "reply_indicator.cancel": "Peruuta",
-  "report.forward": "Forward to {target}",
-  "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
-  "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
+  "report.forward": "Uudelleenohjaa kohteeseen {target}",
+  "report.forward_hint": "Tämä tili on toiselta serveriltä. Haluatko, että myös sinne lähetetään anonymisoitu kopio ilmiantoraportista?",
+  "report.hint": "Ilmianto lähetetään instanssisi moderaattoreille. Voit antaa kuvauksen käyttäjän ilmiantamisen syystä alle:",
   "report.placeholder": "Lisäkommentit",
   "report.submit": "Submit",
   "report.target": "Reporting",
   "search.placeholder": "Hae",
   "search_popout.search_format": "Tarkennettu haku",
-  "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
+  "search_popout.tips.full_text": "Tekstihaku palauttaa statuspäivitykset jotka olet kirjoittanut, lisännyt suosikkeihisi, boostannut tai joissa sinut mainitaan, sekä käyttäjänimet, nimimerkit ja hastagit jotka sisältävät tekstin.",
   "search_popout.tips.hashtag": "hashtagi",
   "search_popout.tips.status": "status",
   "search_popout.tips.text": "Pelkkä tekstihaku palauttaa hakua vastaavat nimimerkit, käyttäjänimet ja hastagit",
   "search_popout.tips.user": "käyttäjä",
-  "search_results.accounts": "People",
-  "search_results.hashtags": "Hashtags",
-  "search_results.statuses": "Toots",
+  "search_results.accounts": "Ihmiset",
+  "search_results.hashtags": "Hashtagit",
+  "search_results.statuses": "Töötit",
   "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
   "standalone.public_title": "Kurkistus sisälle...",
   "status.block": "Block @{name}",
@@ -242,7 +242,7 @@
   "status.mute_conversation": "Mykistä keskustelu",
   "status.open": "Laajenna statuspäivitys",
   "status.pin": "Kiinnitä profiiliin",
-  "status.pinned": "Pinned toot",
+  "status.pinned": "Kiinnitetty töötti",
   "status.reblog": "Buustaa",
   "status.reblogged_by": "{name} buustasi",
   "status.reply": "Vastaa",
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Arkaluontoista sisältöä",
   "status.share": "Jaa",
   "status.show_less": "Näytä vähemmän",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Näytä lisää",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Poista mykistys keskustelulta",
   "status.unpin": "Irrota profiilista",
   "tabs_bar.federated_timeline": "Federated",
@@ -263,7 +265,7 @@
   "upload_area.title": "Raahaa ja pudota tähän ladataksesi",
   "upload_button.label": "Lisää mediaa",
   "upload_form.description": "Anna kuvaus näkörajoitteisia varten",
-  "upload_form.focus": "Crop",
+  "upload_form.focus": "Rajaa",
   "upload_form.undo": "Peru",
   "upload_progress.label": "Ladataan...",
   "video.close": "Sulje video",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index 4df1ef30f..2140ee506 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Contenu sensible",
   "status.share": "Partager",
   "status.show_less": "Replier",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Déplier",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Ne plus masquer la conversation",
   "status.unpin": "Retirer du profil",
   "tabs_bar.federated_timeline": "Fil public global",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index e222ddaea..3c74ba400 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Contido sensible",
   "status.share": "Compartir",
   "status.show_less": "Mostrar menos",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Mostrar máis",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Non acalar a conversa",
   "status.unpin": "Despegar do perfil",
   "tabs_bar.federated_timeline": "Federado",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index b31976c42..8e784b171 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "תוכן רגיש",
   "status.share": "שיתוף",
   "status.show_less": "הראה פחות",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "הראה יותר",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "הסרת השתקת שיחה",
   "status.unpin": "לשחרר מקיבוע באודות",
   "tabs_bar.federated_timeline": "ציר זמן בין-קהילתי",
diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json
index d176a5df6..70d89091e 100644
--- a/app/javascript/mastodon/locales/hr.json
+++ b/app/javascript/mastodon/locales/hr.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Osjetljiv sadržaj",
   "status.share": "Share",
   "status.show_less": "Pokaži manje",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Pokaži više",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Poništi utišavanje razgovora",
   "status.unpin": "Unpin from profile",
   "tabs_bar.federated_timeline": "Federalni",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index a4d2091ef..087305a9a 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Érzékeny tartalom",
   "status.share": "Megosztás",
   "status.show_less": "Kevesebb",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Többet",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Beszélgetés némításának elvonása",
   "status.unpin": "Kitűzés eltávolítása a profilról",
   "tabs_bar.federated_timeline": "Federált",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index b5e9a2b5a..7849d6941 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Կասկածելի բովանդակություն",
   "status.share": "Կիսվել",
   "status.show_less": "Պակաս",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Ավելին",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Ապալռեցնել խոսակցությունը",
   "status.unpin": "Հանել անձնական էջից",
   "tabs_bar.federated_timeline": "Դաշնային",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index 596415cde..6b00d79b6 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Konten sensitif",
   "status.share": "Share",
   "status.show_less": "Tampilkan lebih sedikit",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Tampilkan semua",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Unmute conversation",
   "status.unpin": "Unpin from profile",
   "tabs_bar.federated_timeline": "Gabungan",
diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json
index 4f554b08f..d51b24090 100644
--- a/app/javascript/mastodon/locales/io.json
+++ b/app/javascript/mastodon/locales/io.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Trubliva kontenajo",
   "status.share": "Share",
   "status.show_less": "Montrar mine",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Montrar plue",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Unmute conversation",
   "status.unpin": "Unpin from profile",
   "tabs_bar.federated_timeline": "Federata",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index 6b2532512..0babc7c02 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Materiale sensibile",
   "status.share": "Share",
   "status.show_less": "Mostra meno",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Mostra di più",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Unmute conversation",
   "status.unpin": "Unpin from profile",
   "tabs_bar.federated_timeline": "Federazione",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 04374abc3..2f0caa24d 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -3,7 +3,7 @@
   "account.block_domain": "{domain}全体を非表示",
   "account.blocked": "ブロック済み",
   "account.disclaimer_full": "以下の情報は不正確な可能性があります。",
-  "account.domain_blocked": "Domain hidden",
+  "account.domain_blocked": "ドメイン非表示中",
   "account.edit_profile": "プロフィールを編集",
   "account.follow": "フォロー",
   "account.followers": "フォロワー",
@@ -259,7 +259,9 @@
   "status.sensitive_warning": "閲覧注意",
   "status.share": "共有",
   "status.show_less": "隠す",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "もっと見る",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "会話のミュートを解除",
   "status.unpin": "プロフィールの固定表示を解除",
   "tabs_bar.federated_timeline": "連合",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 05c84fd37..4c56d2a45 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "민감한 미디어",
   "status.share": "공유",
   "status.show_less": "숨기기",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "더 보기",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "이 대화의 뮤트 해제하기",
   "status.unpin": "고정 해제",
   "tabs_bar.federated_timeline": "연합",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 509382670..8906f7351 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Gevoelige inhoud",
   "status.share": "Delen",
   "status.show_less": "Minder tonen",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Meer tonen",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Conversatie niet meer negeren",
   "status.unpin": "Van profielpagina losmaken",
   "tabs_bar.federated_timeline": "Globaal",
diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json
index b7ceb9f73..b14ecaedd 100644
--- a/app/javascript/mastodon/locales/no.json
+++ b/app/javascript/mastodon/locales/no.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Følsomt innhold",
   "status.share": "Del",
   "status.show_less": "Vis mindre",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Vis mer",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Ikke demp samtale",
   "status.unpin": "Angre festing på profilen",
   "tabs_bar.federated_timeline": "Felles",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index c9a15c751..c3d8bcf37 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Contengut sensible",
   "status.share": "Partejar",
   "status.show_less": "Tornar plegar",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Desplegar",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Tornar mostrar la conversacion",
   "status.unpin": "Tirar del perfil",
   "tabs_bar.federated_timeline": "Flux public global",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index 391bc6a28..2ca614899 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -258,8 +258,10 @@
   "status.sensitive_toggle": "Naciśnij aby wyświetlić",
   "status.sensitive_warning": "Wrażliwa zawartość",
   "status.share": "Udostępnij",
-  "status.show_less": "Pokaż mniej",
-  "status.show_more": "Pokaż więcej",
+  "status.show_less": "Zwiń",
+  "status.show_less_all": "Zwiń wszystkie",
+  "status.show_more": "Rozwiń",
+  "status.show_more_all": "Rozwiń wszystkie",
   "status.unmute_conversation": "Cofnij wyciszenie konwersacji",
   "status.unpin": "Odepnij z profilu",
   "tabs_bar.federated_timeline": "Globalne",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index 6406dbea6..67b36fdf2 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Conteúdo sensível",
   "status.share": "Compartilhar",
   "status.show_less": "Mostrar menos",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Mostrar mais",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Desativar silêncio desta conversa",
   "status.unpin": "Desafixar do perfil",
   "tabs_bar.federated_timeline": "Global",
diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json
index f059e7c20..014884637 100644
--- a/app/javascript/mastodon/locales/pt.json
+++ b/app/javascript/mastodon/locales/pt.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Conteúdo sensível",
   "status.share": "Compartilhar",
   "status.show_less": "Mostrar menos",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Mostrar mais",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Deixar de silenciar esta conversa",
   "status.unpin": "Não fixar no perfil",
   "tabs_bar.federated_timeline": "Global",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 06a7d732b..88152a885 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Чувствительный контент",
   "status.share": "Поделиться",
   "status.show_less": "Свернуть",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Развернуть",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Снять глушение с треда",
   "status.unpin": "Открепить от профиля",
   "tabs_bar.federated_timeline": "Глобальная",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index bb86165ad..4ff34012e 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -217,8 +217,8 @@
   "report.placeholder": "Ďalšie komentáre",
   "report.submit": "Poslať",
   "report.target": "Nahlásenie {target}",
-  "search.placeholder": "Hľadať",
-  "search_popout.search_format": "Pokročilý formát vyhľadávania",
+  "search.placeholder": "Hľadaj",
+  "search_popout.search_format": "Pokročilé vyhľadávanie",
   "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
   "search_popout.tips.hashtag": "haštag",
   "search_popout.tips.status": "status",
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Chúlostivý obsah",
   "status.share": "Zdieľať",
   "status.show_less": "Zobraz menej",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Zobraz viac",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Prestať ignorovať konverzáciu",
   "status.unpin": "Odopnúť z profilu",
   "tabs_bar.federated_timeline": "Federovaná",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index a672ae6ca..fc4d0cdc9 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Osetljiv sadržaj",
   "status.share": "Podeli",
   "status.show_less": "Prikaži manje",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Prikaži više",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Uključi prepisku",
   "status.unpin": "Otkači sa profila",
   "tabs_bar.federated_timeline": "Federisano",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index 1e3a3ce2b..ae496d7cc 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Осетљив садржај",
   "status.share": "Подели",
   "status.show_less": "Прикажи мање",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Прикажи више",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Укључи преписку",
   "status.unpin": "Откачи са профила",
   "tabs_bar.federated_timeline": "Федерисано",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 9c51d5b36..e72280136 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -1,9 +1,9 @@
 {
   "account.block": "Blockera @{name}",
   "account.block_domain": "Dölj allt från {domain}",
-  "account.blocked": "Blocked",
+  "account.blocked": "Blockerad",
   "account.disclaimer_full": "Informationen nedan kan spegla användarens profil ofullständigt.",
-  "account.domain_blocked": "Domain hidden",
+  "account.domain_blocked": "Domän gömd",
   "account.edit_profile": "Redigera profil",
   "account.follow": "Följ",
   "account.followers": "Följare",
@@ -15,9 +15,9 @@
   "account.moved_to": "{name} har flyttat till:",
   "account.mute": "Tysta @{name}",
   "account.mute_notifications": "Stäng av notifieringar från @{name}",
-  "account.muted": "Muted",
+  "account.muted": "Nertystad",
   "account.posts": "Inlägg",
-  "account.posts_with_replies": "Toots with replies",
+  "account.posts_with_replies": "Toots med svar",
   "account.report": "Rapportera @{name}",
   "account.requested": "Inväntar godkännande. Klicka för att avbryta följförfrågan",
   "account.share": "Dela @{name}'s profil",
@@ -211,20 +211,20 @@
   "relative_time.minutes": "{number}m",
   "relative_time.seconds": "{number}s",
   "reply_indicator.cancel": "Ångra",
-  "report.forward": "Forward to {target}",
-  "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
-  "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
+  "report.forward": "Vidarebefordra till {target}",
+  "report.forward_hint": "Kontot är från en annan server. Skicka även en anonymiserad kopia av anmälan dit?",
+  "report.hint": "Anmälan skickas till din instans moderatorer. Du kan ge en förklaring till varför du har anmält detta konto nedan:",
   "report.placeholder": "Ytterligare kommentarer",
   "report.submit": "Skicka",
   "report.target": "Rapporterar {target}",
   "search.placeholder": "Sök",
   "search_popout.search_format": "Avancerat sökformat",
-  "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
+  "search_popout.tips.full_text": "Enkel text returnerar statusar där du har skrivit, favoriserat, knuffat eller nämnts samt med matchande användarnamn, visningsnamn och hashtags.",
   "search_popout.tips.hashtag": "hashtag",
   "search_popout.tips.status": "status",
   "search_popout.tips.text": "Enkel text returnerar matchande visningsnamn, användarnamn och hashtags",
   "search_popout.tips.user": "användare",
-  "search_results.accounts": "People",
+  "search_results.accounts": "Människor",
   "search_results.hashtags": "Hashtags",
   "search_results.statuses": "Toots",
   "search_results.total": "{count, number} {count, plural, ett {result} andra {results}}",
@@ -242,7 +242,7 @@
   "status.mute_conversation": "Tysta konversation",
   "status.open": "Utvidga denna status",
   "status.pin": "Fäst i profil",
-  "status.pinned": "Pinned toot",
+  "status.pinned": "Fäst toot",
   "status.reblog": "Knuff",
   "status.reblogged_by": "{name} knuffade",
   "status.reply": "Svara",
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Känsligt innehåll",
   "status.share": "Dela",
   "status.show_less": "Visa mindre",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Visa mer",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Öppna konversation",
   "status.unpin": "Ångra fäst i profil",
   "tabs_bar.federated_timeline": "Förenad",
@@ -263,7 +265,7 @@
   "upload_area.title": "Dra & släpp för att ladda upp",
   "upload_button.label": "Lägg till media",
   "upload_form.description": "Beskriv för synskadade",
-  "upload_form.focus": "Crop",
+  "upload_form.focus": "Beskär",
   "upload_form.undo": "Ångra",
   "upload_progress.label": "Laddar upp...",
   "video.close": "Stäng video",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index cab2ce089..617f4fb78 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Sensitive content",
   "status.share": "Share",
   "status.show_less": "Show less",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Show more",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Unmute conversation",
   "status.unpin": "Unpin from profile",
   "tabs_bar.federated_timeline": "Federated",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 83c10de34..499281ae5 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Hassas içerik",
   "status.share": "Share",
   "status.show_less": "Daha azı",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Daha fazlası",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Unmute conversation",
   "status.unpin": "Unpin from profile",
   "tabs_bar.federated_timeline": "Federe",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index b49f707e1..ff458eb4b 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "Непристойний зміст",
   "status.share": "Share",
   "status.show_less": "Згорнути",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "Розгорнути",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "Зняти глушення з діалогу",
   "status.unpin": "Unpin from profile",
   "tabs_bar.federated_timeline": "Глобальна",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 5ccfbc4f4..d7a08bd17 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "敏感内容",
   "status.share": "分享",
   "status.show_less": "隐藏内容",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "显示内容",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "不再隐藏此对话",
   "status.unpin": "在个人资料页面取消置顶",
   "tabs_bar.federated_timeline": "跨站",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index b105fe426..a02edc2fa 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "敏感內容",
   "status.share": "Share",
   "status.show_less": "減少顯示",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "顯示更多",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "解禁對話",
   "status.unpin": "解除置頂",
   "tabs_bar.federated_timeline": "跨站",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index b0a94f67b..7e61ff32c 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -252,7 +252,9 @@
   "status.sensitive_warning": "敏感內容",
   "status.share": "Share",
   "status.show_less": "看少點",
+  "status.show_less_all": "Show less for all",
   "status.show_more": "看更多",
+  "status.show_more_all": "Show more for all",
   "status.unmute_conversation": "不消音對話",
   "status.unpin": "解除置頂",
   "tabs_bar.federated_timeline": "聯盟",
diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js
index 532f4b2a7..5eadebb81 100644
--- a/app/javascript/mastodon/reducers/compose.js
+++ b/app/javascript/mastodon/reducers/compose.js
@@ -35,6 +35,8 @@ import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrde
 import uuid from '../uuid';
 import { me } from '../initial_state';
 
+const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
+
 const initialState = ImmutableMap({
   mounted: 0,
   sensitive: false,
@@ -135,12 +137,14 @@ const updateSuggestionTags = (state, token) => {
 };
 
 const insertEmoji = (state, position, emojiData) => {
-  const emoji = emojiData.native;
+  const oldText = state.get('text');
+  const needsSpace = emojiData.custom && position > 0 && !allowedAroundShortCode.includes(oldText[position - 1]);
+  const emoji = needsSpace ? ' ' + emojiData.native : emojiData.native;
 
-  return state.withMutations(map => {
-    map.update('text', oldText => `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`);
-    map.set('focusDate', new Date());
-    map.set('idempotencyKey', uuid());
+  return state.merge({
+    text: `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`,
+    focusDate: new Date(),
+    idempotencyKey: uuid(),
   });
 };
 
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index cd0dbbab8..ba1c36d07 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -3422,8 +3422,12 @@ a.status-card {
   img,
   canvas,
   video {
-    max-width: 100vw;
-    max-height: 100vh;
+    max-width: 100%;
+    /*
+    put margins on top and bottom of image to avoid the screen coverd by
+    image.
+     */
+    max-height: 80%;
     width: auto;
     height: auto;
     margin: auto;
@@ -3435,11 +3439,6 @@ a.status-card {
     background: url('~images/void.png') repeat;
     object-fit: contain;
   }
-
-  .react-swipeable-view-container {
-    width: 100vw;
-    height: 100%;
-  }
 }
 
 .media-modal__closer {
@@ -4315,18 +4314,16 @@ a.status-card {
   display: block;
   text-decoration: none;
   color: $ui-secondary-color;
-  height: 100%;
   line-height: 0;
 
   &,
   img {
+    height: 100%;
     width: 100%;
   }
 
   img {
-    position: relative;
     object-fit: cover;
-    height: auto;
   }
 }
 
@@ -5076,6 +5073,12 @@ noscript {
   }
 }
 
+.focal-point-modal {
+  max-width: 80vw;
+  max-height: 80vh;
+  position: relative;
+}
+
 .focal-point {
   position: relative;
   cursor: pointer;
@@ -5085,6 +5088,14 @@ noscript {
     cursor: move;
   }
 
+  img {
+    max-width: 80vw;
+    max-height: 80vh;
+    width: auto;
+    height: auto;
+    margin: auto;
+  }
+
   &__reticle {
     position: absolute;
     width: 100px;
diff --git a/app/models/tag.rb b/app/models/tag.rb
index dc2c8d129..9fa9405d7 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -12,7 +12,7 @@
 class Tag < ApplicationRecord
   has_and_belongs_to_many :statuses
 
-  HASHTAG_NAME_RE = '[[:word:]_]*[[:alpha:]_][[:word:]_]*'
+  HASHTAG_NAME_RE = '[[:word:]_]*[[:alpha:]_·][[:word:]_]*'
   HASHTAG_RE = /(?:^|[^\/\)\w])#(#{HASHTAG_NAME_RE})/i
 
   validates :name, presence: true, uniqueness: true, format: { with: /\A#{HASHTAG_NAME_RE}\z/i }