diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt index ca79b784..862623d2 100644 --- a/fastlane/metadata/en-US/release_notes.txt +++ b/fastlane/metadata/en-US/release_notes.txt @@ -1,10 +1 @@ Enjoy toooting! This version includes following improvements and fixes: -- Added Ukrainian (Slava Ukraini) -- Automatic setting detected language when tooting -- Remember public timeline type selection -- Show diffing of edit history -- Allow hiding boosts and replies in home timeline -- Support toot in RTL languages -- Added notification for admins -- Fix whole word filter matching -- Fix tablet cannot delete toot drafts diff --git a/fastlane/metadata/zh-Hans/release_notes.txt b/fastlane/metadata/zh-Hans/release_notes.txt index 35846c68..d9488dcd 100644 --- a/fastlane/metadata/zh-Hans/release_notes.txt +++ b/fastlane/metadata/zh-Hans/release_notes.txt @@ -1,10 +1 @@ toooting愉快!此版本包括以下改进和修复: -- 增加乌克兰语(Slava Ukraini) -- 自动识别发嘟语言 -- 记住上次公共时间轴选项 -- 显示编辑历史的差异 -- 关注列表可隐藏转嘟和回复 -- 新增管理员推送通知 -- 支持嘟文右到左文字 -- 修复过滤整词功能 -- 修复平板不能删除草稿 diff --git a/package.json b/package.json index b10cfe1c..82ef675d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tooot", - "version": "4.7.0", + "version": "4.7.1", "description": "tooot for Mastodon", "author": "xmflsct ", "license": "GPL-3.0-or-later", diff --git a/src/components/Timeline/Default.tsx b/src/components/Timeline/Default.tsx index 0284cf07..8d209d14 100644 --- a/src/components/Timeline/Default.tsx +++ b/src/components/Timeline/Default.tsx @@ -64,6 +64,7 @@ const TimelineDefault: React.FC = ({ content: '', complete: false }) + const detectedLanguage = useRef(status.language || '') const filtered = queryKey && shouldFilter({ copiableContent, status, queryKey }) if (queryKey && filtered && !highlighted) { @@ -139,6 +140,7 @@ const TimelineDefault: React.FC = ({ ownAccount, spoilerHidden, copiableContent, + detectedLanguage, highlighted, inThread: queryKey?.[1].page === 'Toot', disableDetails, diff --git a/src/components/Timeline/Shared/Context.tsx b/src/components/Timeline/Shared/Context.tsx index f00668d1..218379d1 100644 --- a/src/components/Timeline/Shared/Context.tsx +++ b/src/components/Timeline/Shared/Context.tsx @@ -14,6 +14,7 @@ type ContextType = { content: string complete: boolean }> + detectedLanguage?: React.MutableRefObject highlighted?: boolean inThread?: boolean diff --git a/src/components/Timeline/Shared/Feedback.tsx b/src/components/Timeline/Shared/Feedback.tsx index 40d647e7..ec5bd793 100644 --- a/src/components/Timeline/Shared/Feedback.tsx +++ b/src/components/Timeline/Shared/Feedback.tsx @@ -11,7 +11,7 @@ import { StyleSheet, View } from 'react-native' import StatusContext from './Context' const TimelineFeedback = () => { - const { status, highlighted } = useContext(StatusContext) + const { status, highlighted, detectedLanguage } = useContext(StatusContext) if (!status || !highlighted) return null const { t } = useTranslation('componentTimeline') @@ -80,7 +80,12 @@ const TimelineFeedback = () => { accessibilityHint={t('shared.actionsUsers.history.accessibilityHint')} accessibilityRole='button' style={[styles.text, { marginRight: 0, color: colors.blue }]} - onPress={() => navigation.push('Tab-Shared-History', { id: status.id })} + onPress={() => + navigation.push('Tab-Shared-History', { + id: status.id, + detectedLanguage: detectedLanguage?.current || status.language || '' + }) + } > {t('shared.actionsUsers.history.text', { count: data.length - 1 diff --git a/src/components/Timeline/Shared/Translate.tsx b/src/components/Timeline/Shared/Translate.tsx index d55369dd..f8c62192 100644 --- a/src/components/Timeline/Shared/Translate.tsx +++ b/src/components/Timeline/Shared/Translate.tsx @@ -13,7 +13,7 @@ import { Circle } from 'react-native-animated-spinkit' import StatusContext from './Context' const TimelineTranslate = () => { - const { status, highlighted, copiableContent } = useContext(StatusContext) + const { status, highlighted, copiableContent, detectedLanguage } = useContext(StatusContext) if (!status || !highlighted) return null const { t } = useTranslation('componentTimeline') @@ -38,14 +38,19 @@ const TimelineTranslate = () => { ? [copiableContent?.current.content] : backupTextProcessing() - const [detectedLanguage, setDetectedLanguage] = useState<{ + const [detected, setDetected] = useState<{ language: string confidence: number }>({ language: status.language || '', confidence: 0 }) useEffect(() => { const detect = async () => { const result = await detectLanguage(text.join('\n\n')) - result && setDetectedLanguage(result) + if (result) { + setDetected(result) + if (detectedLanguage) { + detectedLanguage.current = result.language + } + } } detect() }, []) @@ -57,7 +62,7 @@ const TimelineTranslate = () => { const [enabled, setEnabled] = useState(false) const { refetch, data, isFetching, isSuccess, isError } = useTranslateQuery({ - source: detectedLanguage.language, + source: detected.language, target: targetLanguage, text, options: { enabled } @@ -66,9 +71,9 @@ const TimelineTranslate = () => { const devView = () => { return __DEV__ ? ( {` Source: ${ - detectedLanguage?.language + detected?.language }; Confidence: ${ - detectedLanguage?.confidence.toString().slice(0, 5) || 'null' + detected?.confidence.toString().slice(0, 5) || 'null' }; Target: ${targetLanguage}`} ) : null } @@ -78,13 +83,13 @@ const TimelineTranslate = () => { } if ( Platform.OS === 'ios' && - Localization.locale.slice(0, 2).includes(detectedLanguage.language.slice(0, 2)) + Localization.locale.slice(0, 2).includes(detected.language.slice(0, 2)) ) { return devView() } if ( Platform.OS === 'android' && - settingsLanguage?.slice(0, 2).includes(detectedLanguage.language.slice(0, 2)) + settingsLanguage?.slice(0, 2).includes(detected.language.slice(0, 2)) ) { return devView() } diff --git a/src/screens/Tabs/Shared/History.tsx b/src/screens/Tabs/Shared/History.tsx index 1c59cfd8..26325ed2 100644 --- a/src/screens/Tabs/Shared/History.tsx +++ b/src/screens/Tabs/Shared/History.tsx @@ -11,25 +11,45 @@ import { TabSharedStackScreenProps } from '@utils/navigation/navigators' import { useStatusHistory } from '@utils/queryHooks/statusesHistory' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' -import { diffWords } from 'diff' +import { diffChars, diffWords } from 'diff' import React, { useEffect } from 'react' import { useTranslation } from 'react-i18next' import { FlatList, View } from 'react-native' +const SCRIPTS_WITHOUT_BOUNDARIES = [ + 'my', + 'zh', + 'ja', + 'kar', + 'km', + 'lp', + 'phag', + 'pwo', + 'kar', + 'lana', + 'th', + 'bo' +] + const ContentView: React.FC<{ + withoutBoundary: boolean item: Mastodon.StatusHistory prevItem?: Mastodon.StatusHistory -}> = ({ item, prevItem }) => { +}> = ({ withoutBoundary, item, prevItem }) => { const { colors } = useTheme() - const changesSpoiler = diffWords( - removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''), - removeHTML(item.spoiler_text || '') - ) - const changesContent = diffWords( - removeHTML(prevItem?.content || item.content), - removeHTML(item.content) - ) + const changesSpoiler = withoutBoundary + ? diffChars( + removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''), + removeHTML(item.spoiler_text || '') + ) + : diffWords( + removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''), + removeHTML(item.spoiler_text || '') + ) + const changesContent = withoutBoundary + ? diffChars(removeHTML(prevItem?.content || item.content), removeHTML(item.content)) + : diffWords(removeHTML(prevItem?.content || item.content), removeHTML(item.content)) return ( // @ts-ignore @@ -91,7 +111,7 @@ const ContentView: React.FC<{ const TabSharedHistory: React.FC> = ({ navigation, route: { - params: { id } + params: { id, detectedLanguage } } }) => { const { t } = useTranslation('screenTabs') @@ -106,12 +126,20 @@ const TabSharedHistory: React.FC const dataReversed = data ? [...data].reverse() : [] + const withoutBoundary = !!SCRIPTS_WITHOUT_BOUNDARIES.filter(script => + detectedLanguage?.toLocaleLowerCase().startsWith(script) + ).length + return ( ( - + )} ItemSeparatorComponent={ComponentSeparator} /> diff --git a/src/utils/navigation/navigators.ts b/src/utils/navigation/navigators.ts index 0e5d2822..866cea67 100644 --- a/src/utils/navigation/navigators.ts +++ b/src/utils/navigation/navigators.ts @@ -103,6 +103,7 @@ export type TabSharedStackParamList = { } 'Tab-Shared-History': { id: Mastodon.Status['id'] + detectedLanguage: string } 'Tab-Shared-Search': undefined 'Tab-Shared-Toot': {