Merge pull request #1983 from ClearlyClaire/glitch-soc/features/translation
Port “Translate” feature from upstream
This commit is contained in:
		
						commit
						fc0e11abdb
					
				
					 11 changed files with 152 additions and 17 deletions
				
			
		| 
						 | 
					@ -34,6 +34,11 @@ export const STATUS_FETCH_SOURCE_REQUEST = 'STATUS_FETCH_SOURCE_REQUEST';
 | 
				
			||||||
export const STATUS_FETCH_SOURCE_SUCCESS = 'STATUS_FETCH_SOURCE_SUCCESS';
 | 
					export const STATUS_FETCH_SOURCE_SUCCESS = 'STATUS_FETCH_SOURCE_SUCCESS';
 | 
				
			||||||
export const STATUS_FETCH_SOURCE_FAIL    = 'STATUS_FETCH_SOURCE_FAIL';
 | 
					export const STATUS_FETCH_SOURCE_FAIL    = 'STATUS_FETCH_SOURCE_FAIL';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const STATUS_TRANSLATE_REQUEST = 'STATUS_TRANSLATE_REQUEST';
 | 
				
			||||||
 | 
					export const STATUS_TRANSLATE_SUCCESS = 'STATUS_TRANSLATE_SUCCESS';
 | 
				
			||||||
 | 
					export const STATUS_TRANSLATE_FAIL    = 'STATUS_TRANSLATE_FAIL';
 | 
				
			||||||
 | 
					export const STATUS_TRANSLATE_UNDO    = 'STATUS_TRANSLATE_UNDO';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function fetchStatusRequest(id, skipLoading) {
 | 
					export function fetchStatusRequest(id, skipLoading) {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    type: STATUS_FETCH_REQUEST,
 | 
					    type: STATUS_FETCH_REQUEST,
 | 
				
			||||||
| 
						 | 
					@ -310,4 +315,36 @@ export function toggleStatusCollapse(id, isCollapsed) {
 | 
				
			||||||
    id,
 | 
					    id,
 | 
				
			||||||
    isCollapsed,
 | 
					    isCollapsed,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const translateStatus = id => (dispatch, getState) => {
 | 
				
			||||||
 | 
					  dispatch(translateStatusRequest(id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  api(getState).post(`/api/v1/statuses/${id}/translate`).then(response => {
 | 
				
			||||||
 | 
					    dispatch(translateStatusSuccess(id, response.data));
 | 
				
			||||||
 | 
					  }).catch(error => {
 | 
				
			||||||
 | 
					    dispatch(translateStatusFail(id, error));
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const translateStatusRequest = id => ({
 | 
				
			||||||
 | 
					  type: STATUS_TRANSLATE_REQUEST,
 | 
				
			||||||
 | 
					  id,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const translateStatusSuccess = (id, translation) => ({
 | 
				
			||||||
 | 
					  type: STATUS_TRANSLATE_SUCCESS,
 | 
				
			||||||
 | 
					  id,
 | 
				
			||||||
 | 
					  translation,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const translateStatusFail = (id, error) => ({
 | 
				
			||||||
 | 
					  type: STATUS_TRANSLATE_FAIL,
 | 
				
			||||||
 | 
					  id,
 | 
				
			||||||
 | 
					  error,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const undoStatusTranslation = id => ({
 | 
				
			||||||
 | 
					  type: STATUS_TRANSLATE_UNDO,
 | 
				
			||||||
 | 
					  id,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,6 +83,7 @@ class Status extends ImmutablePureComponent {
 | 
				
			||||||
    onEmbed: PropTypes.func,
 | 
					    onEmbed: PropTypes.func,
 | 
				
			||||||
    onHeightChange: PropTypes.func,
 | 
					    onHeightChange: PropTypes.func,
 | 
				
			||||||
    onToggleHidden: PropTypes.func,
 | 
					    onToggleHidden: PropTypes.func,
 | 
				
			||||||
 | 
					    onTranslate: PropTypes.func,
 | 
				
			||||||
    onInteractionModal: PropTypes.func,
 | 
					    onInteractionModal: PropTypes.func,
 | 
				
			||||||
    muted: PropTypes.bool,
 | 
					    muted: PropTypes.bool,
 | 
				
			||||||
    hidden: PropTypes.bool,
 | 
					    hidden: PropTypes.bool,
 | 
				
			||||||
| 
						 | 
					@ -472,6 +473,10 @@ class Status extends ImmutablePureComponent {
 | 
				
			||||||
    this.node = c;
 | 
					    this.node = c;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleTranslate = () => {
 | 
				
			||||||
 | 
					    this.props.onTranslate(this.props.status);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  renderLoadingMediaGallery () {
 | 
					  renderLoadingMediaGallery () {
 | 
				
			||||||
    return <div className='media-gallery' style={{ height: '110px' }} />;
 | 
					    return <div className='media-gallery' style={{ height: '110px' }} />;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -788,6 +793,7 @@ class Status extends ImmutablePureComponent {
 | 
				
			||||||
            mediaIcons={contentMediaIcons}
 | 
					            mediaIcons={contentMediaIcons}
 | 
				
			||||||
            expanded={isExpanded}
 | 
					            expanded={isExpanded}
 | 
				
			||||||
            onExpandedToggle={this.handleExpandedToggle}
 | 
					            onExpandedToggle={this.handleExpandedToggle}
 | 
				
			||||||
 | 
					            onTranslate={this.handleTranslate}
 | 
				
			||||||
            parseClick={parseClick}
 | 
					            parseClick={parseClick}
 | 
				
			||||||
            disabled={!router}
 | 
					            disabled={!router}
 | 
				
			||||||
            tagLinks={settings.get('tag_misleading_links')}
 | 
					            tagLinks={settings.get('tag_misleading_links')}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import { FormattedMessage } from 'react-intl';
 | 
					import { FormattedMessage, injectIntl } from 'react-intl';
 | 
				
			||||||
import Permalink from './permalink';
 | 
					import Permalink from './permalink';
 | 
				
			||||||
import classnames from 'classnames';
 | 
					import classnames from 'classnames';
 | 
				
			||||||
import Icon from 'flavours/glitch/components/icon';
 | 
					import Icon from 'flavours/glitch/components/icon';
 | 
				
			||||||
import { autoPlayGif } from 'flavours/glitch/initial_state';
 | 
					import { autoPlayGif, languages as preloadedLanguages, translationEnabled } from 'flavours/glitch/initial_state';
 | 
				
			||||||
import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';
 | 
					import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const textMatchesTarget = (text, origin, host) => {
 | 
					const textMatchesTarget = (text, origin, host) => {
 | 
				
			||||||
| 
						 | 
					@ -62,13 +62,56 @@ const isLinkMisleading = (link) => {
 | 
				
			||||||
  return !(textMatchesTarget(text, origin, host) || textMatchesTarget(text.toLowerCase(), origin, host));
 | 
					  return !(textMatchesTarget(text, origin, host) || textMatchesTarget(text.toLowerCase(), origin, host));
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class StatusContent extends React.PureComponent {
 | 
					class TranslateButton extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static propTypes = {
 | 
				
			||||||
 | 
					    translation: ImmutablePropTypes.map,
 | 
				
			||||||
 | 
					    onClick: PropTypes.func,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  render () {
 | 
				
			||||||
 | 
					    const { translation, onClick } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (translation) {
 | 
				
			||||||
 | 
					      const language     = preloadedLanguages.find(lang => lang[0] === translation.get('detected_source_language'));
 | 
				
			||||||
 | 
					      const languageName = language ? language[2] : translation.get('detected_source_language');
 | 
				
			||||||
 | 
					      const provider     = translation.get('provider');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return (
 | 
				
			||||||
 | 
					        <div className='translate-button'>
 | 
				
			||||||
 | 
					          <div className='translate-button__meta'>
 | 
				
			||||||
 | 
					            <FormattedMessage id='status.translated_from_with' defaultMessage='Translated from {lang} using {provider}' values={{ lang: languageName, provider }} />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <button className='link-button' onClick={onClick}>
 | 
				
			||||||
 | 
					            <FormattedMessage id='status.show_original' defaultMessage='Show original' />
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <button className='status__content__read-more-button' onClick={onClick}>
 | 
				
			||||||
 | 
					        <FormattedMessage id='status.translate' defaultMessage='Translate' />
 | 
				
			||||||
 | 
					      </button>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default @injectIntl
 | 
				
			||||||
 | 
					class StatusContent extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static contextTypes = {
 | 
				
			||||||
 | 
					    identity: PropTypes.object,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    status: ImmutablePropTypes.map.isRequired,
 | 
					    status: ImmutablePropTypes.map.isRequired,
 | 
				
			||||||
    expanded: PropTypes.bool,
 | 
					    expanded: PropTypes.bool,
 | 
				
			||||||
    collapsed: PropTypes.bool,
 | 
					    collapsed: PropTypes.bool,
 | 
				
			||||||
    onExpandedToggle: PropTypes.func,
 | 
					    onExpandedToggle: PropTypes.func,
 | 
				
			||||||
 | 
					    onTranslate: PropTypes.func,
 | 
				
			||||||
    media: PropTypes.node,
 | 
					    media: PropTypes.node,
 | 
				
			||||||
    extraMedia: PropTypes.node,
 | 
					    extraMedia: PropTypes.node,
 | 
				
			||||||
    mediaIcons: PropTypes.arrayOf(PropTypes.string),
 | 
					    mediaIcons: PropTypes.arrayOf(PropTypes.string),
 | 
				
			||||||
| 
						 | 
					@ -77,6 +120,7 @@ export default class StatusContent extends React.PureComponent {
 | 
				
			||||||
    onUpdate: PropTypes.func,
 | 
					    onUpdate: PropTypes.func,
 | 
				
			||||||
    tagLinks: PropTypes.bool,
 | 
					    tagLinks: PropTypes.bool,
 | 
				
			||||||
    rewriteMentions: PropTypes.string,
 | 
					    rewriteMentions: PropTypes.string,
 | 
				
			||||||
 | 
					    intl: PropTypes.object,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static defaultProps = {
 | 
					  static defaultProps = {
 | 
				
			||||||
| 
						 | 
					@ -249,6 +293,10 @@ export default class StatusContent extends React.PureComponent {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleTranslate = () => {
 | 
				
			||||||
 | 
					    this.props.onTranslate();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setContentsRef = (c) => {
 | 
					  setContentsRef = (c) => {
 | 
				
			||||||
    this.contentsNode = c;
 | 
					    this.contentsNode = c;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -263,18 +311,24 @@ export default class StatusContent extends React.PureComponent {
 | 
				
			||||||
      disabled,
 | 
					      disabled,
 | 
				
			||||||
      tagLinks,
 | 
					      tagLinks,
 | 
				
			||||||
      rewriteMentions,
 | 
					      rewriteMentions,
 | 
				
			||||||
 | 
					      intl,
 | 
				
			||||||
    } = this.props;
 | 
					    } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;
 | 
					    const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;
 | 
				
			||||||
 | 
					    const renderTranslate = translationEnabled && this.context.identity.signedIn && this.props.onTranslate && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('contentHtml').length > 0 && status.get('language') !== null && intl.locale !== status.get('language');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const content = { __html: status.get('contentHtml') };
 | 
					    const content = { __html: status.get('translation') ? status.getIn(['translation', 'content']) : status.get('contentHtml') };
 | 
				
			||||||
    const spoilerContent = { __html: status.get('spoilerHtml') };
 | 
					    const spoilerContent = { __html: status.get('spoilerHtml') };
 | 
				
			||||||
    const lang = status.get('language');
 | 
					    const lang = status.get('translation') ? intl.locale : status.get('language');
 | 
				
			||||||
    const classNames = classnames('status__content', {
 | 
					    const classNames = classnames('status__content', {
 | 
				
			||||||
      'status__content--with-action': parseClick && !disabled,
 | 
					      'status__content--with-action': parseClick && !disabled,
 | 
				
			||||||
      'status__content--with-spoiler': status.get('spoiler_text').length > 0,
 | 
					      'status__content--with-spoiler': status.get('spoiler_text').length > 0,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const translateButton = renderTranslate && (
 | 
				
			||||||
 | 
					      <TranslateButton onClick={this.handleTranslate} translation={status.get('translation')} />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (status.get('spoiler_text').length > 0) {
 | 
					    if (status.get('spoiler_text').length > 0) {
 | 
				
			||||||
      let mentionsPlaceholder = '';
 | 
					      let mentionsPlaceholder = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -350,11 +404,11 @@ export default class StatusContent extends React.PureComponent {
 | 
				
			||||||
              onMouseLeave={this.handleMouseLeave}
 | 
					              onMouseLeave={this.handleMouseLeave}
 | 
				
			||||||
              lang={lang}
 | 
					              lang={lang}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
 | 
					            {!hidden && translateButton}
 | 
				
			||||||
            {media}
 | 
					            {media}
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          {extraMedia}
 | 
					          {extraMedia}
 | 
				
			||||||
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } else if (parseClick) {
 | 
					    } else if (parseClick) {
 | 
				
			||||||
| 
						 | 
					@ -375,6 +429,7 @@ export default class StatusContent extends React.PureComponent {
 | 
				
			||||||
            onMouseLeave={this.handleMouseLeave}
 | 
					            onMouseLeave={this.handleMouseLeave}
 | 
				
			||||||
            lang={lang}
 | 
					            lang={lang}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
 | 
					          {translateButton}
 | 
				
			||||||
          {media}
 | 
					          {media}
 | 
				
			||||||
          {extraMedia}
 | 
					          {extraMedia}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
| 
						 | 
					@ -395,6 +450,7 @@ export default class StatusContent extends React.PureComponent {
 | 
				
			||||||
            onMouseLeave={this.handleMouseLeave}
 | 
					            onMouseLeave={this.handleMouseLeave}
 | 
				
			||||||
            lang={lang}
 | 
					            lang={lang}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
 | 
					          {translateButton}
 | 
				
			||||||
          {media}
 | 
					          {media}
 | 
				
			||||||
          {extraMedia}
 | 
					          {extraMedia}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,9 @@ import {
 | 
				
			||||||
  deleteStatus,
 | 
					  deleteStatus,
 | 
				
			||||||
  hideStatus,
 | 
					  hideStatus,
 | 
				
			||||||
  revealStatus,
 | 
					  revealStatus,
 | 
				
			||||||
  editStatus
 | 
					  editStatus,
 | 
				
			||||||
 | 
					  translateStatus,
 | 
				
			||||||
 | 
					  undoStatusTranslation,
 | 
				
			||||||
} from 'flavours/glitch/actions/statuses';
 | 
					} from 'flavours/glitch/actions/statuses';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  initAddFilter,
 | 
					  initAddFilter,
 | 
				
			||||||
| 
						 | 
					@ -187,6 +189,14 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
 | 
				
			||||||
    dispatch(editStatus(status.get('id'), history));
 | 
					    dispatch(editStatus(status.get('id'), history));
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onTranslate (status) {
 | 
				
			||||||
 | 
					    if (status.get('translation')) {
 | 
				
			||||||
 | 
					      dispatch(undoStatusTranslation(status.get('id')));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      dispatch(translateStatus(status.get('id')));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onDirect (account, router) {
 | 
					  onDirect (account, router) {
 | 
				
			||||||
    dispatch(directCompose(account, router));
 | 
					    dispatch(directCompose(account, router));
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,7 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			||||||
    onOpenMedia: PropTypes.func.isRequired,
 | 
					    onOpenMedia: PropTypes.func.isRequired,
 | 
				
			||||||
    onOpenVideo: PropTypes.func.isRequired,
 | 
					    onOpenVideo: PropTypes.func.isRequired,
 | 
				
			||||||
    onToggleHidden: PropTypes.func,
 | 
					    onToggleHidden: PropTypes.func,
 | 
				
			||||||
 | 
					    onTranslate: PropTypes.func.isRequired,
 | 
				
			||||||
    expanded: PropTypes.bool,
 | 
					    expanded: PropTypes.bool,
 | 
				
			||||||
    measureHeight: PropTypes.bool,
 | 
					    measureHeight: PropTypes.bool,
 | 
				
			||||||
    onHeightChange: PropTypes.func,
 | 
					    onHeightChange: PropTypes.func,
 | 
				
			||||||
| 
						 | 
					@ -112,6 +113,11 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			||||||
    window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
 | 
					    window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleTranslate = () => {
 | 
				
			||||||
 | 
					    const { onTranslate, status } = this.props;
 | 
				
			||||||
 | 
					    onTranslate(status);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;
 | 
					    const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;
 | 
				
			||||||
    const { expanded, onToggleHidden, settings, usingPiP, intl } = this.props;
 | 
					    const { expanded, onToggleHidden, settings, usingPiP, intl } = this.props;
 | 
				
			||||||
| 
						 | 
					@ -305,6 +311,7 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			||||||
            expanded={expanded}
 | 
					            expanded={expanded}
 | 
				
			||||||
            collapsed={false}
 | 
					            collapsed={false}
 | 
				
			||||||
            onExpandedToggle={onToggleHidden}
 | 
					            onExpandedToggle={onToggleHidden}
 | 
				
			||||||
 | 
					            onTranslate={this.handleTranslate}
 | 
				
			||||||
            parseClick={this.parseClick}
 | 
					            parseClick={this.parseClick}
 | 
				
			||||||
            onUpdate={this.handleChildUpdate}
 | 
					            onUpdate={this.handleChildUpdate}
 | 
				
			||||||
            tagLinks={settings.get('tag_misleading_links')}
 | 
					            tagLinks={settings.get('tag_misleading_links')}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,9 @@ import {
 | 
				
			||||||
  deleteStatus,
 | 
					  deleteStatus,
 | 
				
			||||||
  editStatus,
 | 
					  editStatus,
 | 
				
			||||||
  hideStatus,
 | 
					  hideStatus,
 | 
				
			||||||
  revealStatus
 | 
					  revealStatus,
 | 
				
			||||||
 | 
					  translateStatus,
 | 
				
			||||||
 | 
					  undoStatusTranslation,
 | 
				
			||||||
} from 'flavours/glitch/actions/statuses';
 | 
					} from 'flavours/glitch/actions/statuses';
 | 
				
			||||||
import { initMuteModal } from 'flavours/glitch/actions/mutes';
 | 
					import { initMuteModal } from 'flavours/glitch/actions/mutes';
 | 
				
			||||||
import { initBlockModal } from 'flavours/glitch/actions/blocks';
 | 
					import { initBlockModal } from 'flavours/glitch/actions/blocks';
 | 
				
			||||||
| 
						 | 
					@ -437,6 +439,16 @@ class Status extends ImmutablePureComponent {
 | 
				
			||||||
    this.setState({ isExpanded: !isExpanded, threadExpanded: !isExpanded });
 | 
					    this.setState({ isExpanded: !isExpanded, threadExpanded: !isExpanded });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleTranslate = status => {
 | 
				
			||||||
 | 
					    const { dispatch } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (status.get('translation')) {
 | 
				
			||||||
 | 
					      dispatch(undoStatusTranslation(status.get('id')));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      dispatch(translateStatus(status.get('id')));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleBlockClick = (status) => {
 | 
					  handleBlockClick = (status) => {
 | 
				
			||||||
    const { dispatch } = this.props;
 | 
					    const { dispatch } = this.props;
 | 
				
			||||||
    const account = status.get('account');
 | 
					    const account = status.get('account');
 | 
				
			||||||
| 
						 | 
					@ -666,6 +678,7 @@ class Status extends ImmutablePureComponent {
 | 
				
			||||||
                  onOpenMedia={this.handleOpenMedia}
 | 
					                  onOpenMedia={this.handleOpenMedia}
 | 
				
			||||||
                  expanded={isExpanded}
 | 
					                  expanded={isExpanded}
 | 
				
			||||||
                  onToggleHidden={this.handleToggleHidden}
 | 
					                  onToggleHidden={this.handleToggleHidden}
 | 
				
			||||||
 | 
					                  onTranslate={this.handleTranslate}
 | 
				
			||||||
                  domain={domain}
 | 
					                  domain={domain}
 | 
				
			||||||
                  showMedia={this.state.showMedia}
 | 
					                  showMedia={this.state.showMedia}
 | 
				
			||||||
                  onToggleMediaVisibility={this.handleToggleMediaVisibility}
 | 
					                  onToggleMediaVisibility={this.handleToggleMediaVisibility}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,6 +79,7 @@
 | 
				
			||||||
 * @property {boolean} use_blurhash
 | 
					 * @property {boolean} use_blurhash
 | 
				
			||||||
 * @property {boolean=} use_pending_items
 | 
					 * @property {boolean=} use_pending_items
 | 
				
			||||||
 * @property {string} version
 | 
					 * @property {string} version
 | 
				
			||||||
 | 
					 * @property {boolean} translation_enabled
 | 
				
			||||||
 * @property {object} local_settings
 | 
					 * @property {object} local_settings
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -137,6 +138,7 @@ export const unfollowModal = getMeta('unfollow_modal');
 | 
				
			||||||
export const useBlurhash = getMeta('use_blurhash');
 | 
					export const useBlurhash = getMeta('use_blurhash');
 | 
				
			||||||
export const usePendingItems = getMeta('use_pending_items');
 | 
					export const usePendingItems = getMeta('use_pending_items');
 | 
				
			||||||
export const version = getMeta('version');
 | 
					export const version = getMeta('version');
 | 
				
			||||||
 | 
					export const translationEnabled = getMeta('translation_enabled');
 | 
				
			||||||
export const languages = initialState?.languages;
 | 
					export const languages = initialState?.languages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Glitch-soc-specific settings
 | 
					// Glitch-soc-specific settings
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,8 @@ import {
 | 
				
			||||||
  STATUS_REVEAL,
 | 
					  STATUS_REVEAL,
 | 
				
			||||||
  STATUS_HIDE,
 | 
					  STATUS_HIDE,
 | 
				
			||||||
  STATUS_COLLAPSE,
 | 
					  STATUS_COLLAPSE,
 | 
				
			||||||
 | 
					  STATUS_TRANSLATE_SUCCESS,
 | 
				
			||||||
 | 
					  STATUS_TRANSLATE_UNDO,
 | 
				
			||||||
  STATUS_FETCH_REQUEST,
 | 
					  STATUS_FETCH_REQUEST,
 | 
				
			||||||
  STATUS_FETCH_FAIL,
 | 
					  STATUS_FETCH_FAIL,
 | 
				
			||||||
} from 'flavours/glitch/actions/statuses';
 | 
					} from 'flavours/glitch/actions/statuses';
 | 
				
			||||||
| 
						 | 
					@ -85,6 +87,10 @@ export default function statuses(state = initialState, action) {
 | 
				
			||||||
    return state.setIn([action.id, 'collapsed'], action.isCollapsed);
 | 
					    return state.setIn([action.id, 'collapsed'], action.isCollapsed);
 | 
				
			||||||
  case TIMELINE_DELETE:
 | 
					  case TIMELINE_DELETE:
 | 
				
			||||||
    return deleteStatus(state, action.id, action.references);
 | 
					    return deleteStatus(state, action.id, action.references);
 | 
				
			||||||
 | 
					  case STATUS_TRANSLATE_SUCCESS:
 | 
				
			||||||
 | 
					    return state.setIn([action.id, 'translation'], fromJS(action.translation));
 | 
				
			||||||
 | 
					  case STATUS_TRANSLATE_UNDO:
 | 
				
			||||||
 | 
					    return state.deleteIn([action.id, 'translation']);
 | 
				
			||||||
  default:
 | 
					  default:
 | 
				
			||||||
    return state;
 | 
					    return state;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@
 | 
				
			||||||
  display: block;
 | 
					  display: block;
 | 
				
			||||||
  font-size: 15px;
 | 
					  font-size: 15px;
 | 
				
			||||||
  line-height: 20px;
 | 
					  line-height: 20px;
 | 
				
			||||||
  color: $ui-highlight-color;
 | 
					  color: $highlight-text-color;
 | 
				
			||||||
  border: 0;
 | 
					  border: 0;
 | 
				
			||||||
  background: transparent;
 | 
					  background: transparent;
 | 
				
			||||||
  padding: 0;
 | 
					  padding: 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -206,15 +206,13 @@
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.status__content__edited-label {
 | 
					.translate-button {
 | 
				
			||||||
  display: block;
 | 
					  margin-top: 16px;
 | 
				
			||||||
  cursor: default;
 | 
					 | 
				
			||||||
  font-size: 15px;
 | 
					  font-size: 15px;
 | 
				
			||||||
  line-height: 20px;
 | 
					  line-height: 20px;
 | 
				
			||||||
  padding: 0;
 | 
					  display: flex;
 | 
				
			||||||
  padding-top: 8px;
 | 
					  justify-content: space-between;
 | 
				
			||||||
  color: $dark-text-color;
 | 
					  color: $dark-text-color;
 | 
				
			||||||
  font-weight: 500;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.status__content__spoiler-link {
 | 
					.status__content__spoiler-link {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -268,7 +268,7 @@ a.button.logo-button {
 | 
				
			||||||
  border: 0;
 | 
					  border: 0;
 | 
				
			||||||
  background: transparent;
 | 
					  background: transparent;
 | 
				
			||||||
  padding: 0;
 | 
					  padding: 0;
 | 
				
			||||||
  padding-top: 8px;
 | 
					  padding-top: 16px;
 | 
				
			||||||
  text-decoration: none;
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:hover,
 | 
					  &:hover,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue