Experimental feature: translate bio

This commit is contained in:
Lim Chee Aun 2023-03-29 01:12:59 +08:00
parent 9fc8154237
commit a41871ae4b
4 changed files with 67 additions and 15 deletions

View file

@ -9,10 +9,10 @@ import {
} from '@szhsin/react-menu';
import { useEffect, useRef, useState } from 'preact/hooks';
import RelativeTime from '../components/relative-time';
import { api } from '../utils/api';
import emojifyText from '../utils/emojify-text';
import enhanceContent from '../utils/enhance-content';
import getHTMLText from '../utils/getHTMLText';
import handleContentLinks from '../utils/handle-content-links';
import niceDateTime from '../utils/nice-date-time';
import shortenNumber from '../utils/shorten-number';
@ -24,6 +24,8 @@ import AccountBlock from './account-block';
import Avatar from './avatar';
import Icon from './icon';
import Link from './link';
import Modal from './modal';
import TranslationBlock from './translation-block';
const MUTE_DURATIONS = [
1000 * 60 * 5, // 5 minutes
@ -389,7 +391,7 @@ function RelatedActions({ info, instance, authenticated }) {
const [relationship, setRelationship] = useState(null);
const [familiarFollowers, setFamiliarFollowers] = useState([]);
const { id, acct, url, username, locked, lastStatusAt } = info;
const { id, acct, url, username, locked, lastStatusAt, note, fields } = info;
const accountID = useRef(id);
const {
@ -484,6 +486,8 @@ function RelatedActions({ info, instance, authenticated }) {
const loading = relationshipUIState === 'loading';
const menuInstanceRef = useRef(null);
const [showTranslatedBio, setShowTranslatedBio] = useState(false);
return (
<>
{familiarFollowers?.length > 0 && (
@ -571,6 +575,14 @@ function RelatedActions({ info, instance, authenticated }) {
<Icon icon="at" />
<span>Mention @{username}</span>
</MenuItem>
<MenuItem
onClick={() => {
setShowTranslatedBio(true);
}}
>
<Icon icon="translate" />
<span>Translate bio</span>
</MenuItem>
<MenuDivider />
</>
)}
@ -816,6 +828,18 @@ function RelatedActions({ info, instance, authenticated }) {
)}
</span>
</p>
{!!showTranslatedBio && (
<Modal
class="light"
onClick={(e) => {
if (e.target === e.currentTarget) {
setShowTranslatedBio(false);
}
}}
>
<TranslatedBioSheet note={note} fields={fields} />
</Modal>
)}
</>
);
}
@ -850,4 +874,30 @@ function niceAccountURL(url) {
);
}
function TranslatedBioSheet({ note, fields }) {
const fieldsText =
fields
?.map(({ name, value }) => `${name}\n${getHTMLText(value)}`)
.join('\n\n') || '';
const text = getHTMLText(note) + (fieldsText ? `\n\n${fieldsText}` : '');
return (
<div class="sheet">
<header>
<h2>Translated Bio</h2>
</header>
<main>
<p
style={{
whiteSpace: 'pre-wrap',
}}
>
{text}
</p>
<TranslationBlock forceTranslate text={text} />
</main>
</div>
);
}
export default AccountInfo;

View file

@ -25,6 +25,7 @@ import NameText from '../components/name-text';
import { api } from '../utils/api';
import enhanceContent from '../utils/enhance-content';
import getTranslateTargetLanguage from '../utils/get-translate-target-language';
import getHTMLText from '../utils/getHTMLText';
import handleContentLinks from '../utils/handle-content-links';
import htmlContentLength from '../utils/html-content-length';
import niceDateTime from '../utils/nice-date-time';
@ -1695,18 +1696,6 @@ function nicePostURL(url) {
const unfurlMastodonLink = throttle(_unfurlMastodonLink);
const div = document.createElement('div');
export function getHTMLText(html) {
if (!html) return '';
div.innerHTML = html
.replace(/<\/p>/g, '</p>\n\n')
.replace(/<\/li>/g, '</li>\n');
div.querySelectorAll('br').forEach((br) => {
br.replaceWith('\n');
});
return div.innerText.replace(/[\r\n]{3,}/g, '\n\n').trim();
}
const root = document.documentElement;
const defaultBoundingBoxPadding = 8;
function safeBoundingBoxPadding() {

13
src/utils/getHTMLText.jsx Normal file
View file

@ -0,0 +1,13 @@
const div = document.createElement('div');
function getHTMLText(html) {
if (!html) return '';
div.innerHTML = html
.replace(/<\/p>/g, '</p>\n\n')
.replace(/<\/li>/g, '</li>\n');
div.querySelectorAll('br').forEach((br) => {
br.replaceWith('\n');
});
return div.innerText.replace(/[\r\n]{3,}/g, '\n\n').trim();
}
export default getHTMLText;

View file

@ -1,4 +1,4 @@
import { getHTMLText } from '../components/status';
import getHTMLText from './getHTMLText';
function statusPeek(status) {
const { spoilerText, content, poll, mediaAttachments } = status;