mirror of
https://github.com/mastodon/mastodon.git
synced 2025-07-18 02:08:16 +00:00
Compare commits
6 Commits
d2cf460738
...
57f03145a9
Author | SHA1 | Date | |
---|---|---|---|
![]() |
57f03145a9 | ||
![]() |
74fc4dbacf | ||
![]() |
f2a151805f | ||
![]() |
46e3c18071 | ||
![]() |
6c38ab5b6b | ||
![]() |
5e50840986 |
|
@ -10,6 +10,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
|
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
|
||||||
|
import { translateStatusSuccess } from 'mastodon/actions/statuses';
|
||||||
|
import { undoStatusTranslation } from 'mastodon/actions/statuses';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { Poll } from 'mastodon/components/poll';
|
import { Poll } from 'mastodon/components/poll';
|
||||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
|
@ -17,6 +19,8 @@ import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_s
|
||||||
|
|
||||||
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
|
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
|
||||||
|
|
||||||
|
const supportsTranslator = 'Translator' in globalThis;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {any} status
|
* @param {any} status
|
||||||
|
@ -64,10 +68,18 @@ class TranslateButton extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
languages: state.getIn(['server', 'translationLanguages', 'items']),
|
languages: supportsTranslator ? new Map() : state.getIn(['server', 'translationLanguages', 'items']),
|
||||||
});
|
});
|
||||||
|
|
||||||
class StatusContent extends PureComponent {
|
class StatusContent extends PureComponent {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
showTranslateButton: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
identity: identityContextPropShape,
|
identity: identityContextPropShape,
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
|
@ -161,8 +173,34 @@ class StatusContent extends PureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount () {
|
async componentDidMount () {
|
||||||
this._updateStatusLinks();
|
this._updateStatusLinks();
|
||||||
|
|
||||||
|
const { status, intl, languages } = this.props;
|
||||||
|
const contentLocale = intl.locale.replace(/[_-].*/, '');
|
||||||
|
const targetLanguages = languages?.get(status.get('language') || 'und');
|
||||||
|
|
||||||
|
const shouldAttemptTranslate =
|
||||||
|
this.props.onTranslate &&
|
||||||
|
this.props.identity.signedIn &&
|
||||||
|
['public', 'unlisted'].includes(status.get('visibility')) &&
|
||||||
|
status.get('search_index').trim().length > 0;
|
||||||
|
|
||||||
|
if (!shouldAttemptTranslate) return;
|
||||||
|
|
||||||
|
let available = false;
|
||||||
|
if (supportsTranslator) {
|
||||||
|
available = (await Translator.availability({
|
||||||
|
sourceLanguage: status.get('language'),
|
||||||
|
targetLanguage: contentLocale,
|
||||||
|
})) !== 'unavailable';
|
||||||
|
} else {
|
||||||
|
available = targetLanguages?.includes(contentLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (available) {
|
||||||
|
this.setState({ showTranslateButton: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate () {
|
componentDidUpdate () {
|
||||||
|
@ -212,8 +250,37 @@ class StatusContent extends PureComponent {
|
||||||
this.startXY = null;
|
this.startXY = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
handleTranslate = () => {
|
handleTranslate = async () => {
|
||||||
this.props.onTranslate();
|
if (!supportsTranslator) {
|
||||||
|
this.props.onTranslate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { intl, status, statusContent } = this.props;
|
||||||
|
|
||||||
|
if (status.get('translation')) {
|
||||||
|
this.props.dispatch(undoStatusTranslation(status.get('id'), status.get('poll')));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourceLanguage = status.get('language');
|
||||||
|
const targetLanguage = intl.locale.replace(/[_-].*/, '');
|
||||||
|
try {
|
||||||
|
const translator = await Translator.create({
|
||||||
|
sourceLanguage,
|
||||||
|
targetLanguage,
|
||||||
|
});
|
||||||
|
const translatedText = await translator.translate(statusContent);
|
||||||
|
const translation = {
|
||||||
|
content: translatedText,
|
||||||
|
provider: 'Translator API',
|
||||||
|
detected_source_language: sourceLanguage,
|
||||||
|
language: targetLanguage,
|
||||||
|
};
|
||||||
|
this.props.dispatch(translateStatusSuccess(status.get('id'), translation));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setRef = (c) => {
|
setRef = (c) => {
|
||||||
|
@ -221,12 +288,9 @@ class StatusContent extends PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, intl, statusContent } = this.props;
|
const { status, statusContent } = this.props;
|
||||||
|
|
||||||
const renderReadMore = this.props.onClick && status.get('collapsed');
|
const renderReadMore = this.props.onClick && status.get('collapsed');
|
||||||
const contentLocale = intl.locale.replace(/[_-].*/, '');
|
|
||||||
const targetLanguages = this.props.languages?.get(status.get('language') || 'und');
|
|
||||||
const renderTranslate = this.props.onTranslate && this.props.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale);
|
|
||||||
|
|
||||||
const content = { __html: statusContent ?? getStatusContent(status) };
|
const content = { __html: statusContent ?? getStatusContent(status) };
|
||||||
const language = status.getIn(['translation', 'language']) || status.get('language');
|
const language = status.getIn(['translation', 'language']) || status.get('language');
|
||||||
|
@ -241,7 +305,7 @@ class StatusContent extends PureComponent {
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
||||||
const translateButton = renderTranslate && (
|
const translateButton = this.state.showTranslateButton && (
|
||||||
<TranslateButton onClick={this.handleTranslate} translation={status.get('translation')} />
|
<TranslateButton onClick={this.handleTranslate} translation={status.get('translation')} />
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -272,8 +336,7 @@ class StatusContent extends PureComponent {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusContent))));
|
export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusContent))));
|
||||||
|
|
|
@ -2848,7 +2848,6 @@ a.account__display-name {
|
||||||
&__pane {
|
&__pane {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
pointer-events: none;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
min-width: 285px;
|
min-width: 285px;
|
||||||
|
@ -2860,7 +2859,6 @@ a.account__display-name {
|
||||||
&__inner {
|
&__inner {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 285px;
|
width: 285px;
|
||||||
pointer-events: auto;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user