[APP-718] Improvements and fixes to language handling (#931)
* Add locale helpers for narrowing languages * Add a translate link to posts in a different language * Update language filtering to use narrowing when multiple declared * Fix a few more RTL layout cases * Fix types
This commit is contained in:
parent
48844aa4c7
commit
ed5a88d9d8
9 changed files with 174 additions and 88 deletions
|
@ -96,7 +96,7 @@ export const ListCard = ({
|
|||
{descriptionRichText ? (
|
||||
<View style={styles.details}>
|
||||
<RichTextCom
|
||||
style={pal.text}
|
||||
style={[pal.text, s.flex1]}
|
||||
numberOfLines={20}
|
||||
richText={descriptionRichText}
|
||||
/>
|
||||
|
|
|
@ -347,6 +347,7 @@ const styles = StyleSheet.create({
|
|||
borderTopWidth: 1,
|
||||
},
|
||||
headerDescription: {
|
||||
flex: 1,
|
||||
marginTop: 8,
|
||||
},
|
||||
headerBtns: {
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, {useCallback, useMemo} from 'react'
|
|||
import {observer} from 'mobx-react-lite'
|
||||
import {AccessibilityActionEvent, Linking, StyleSheet, View} from 'react-native'
|
||||
import Clipboard from '@react-native-clipboard/clipboard'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {AtUri, AppBskyFeedDefs} from '@atproto/api'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
|
@ -18,6 +18,7 @@ import {s} from 'lib/styles'
|
|||
import {ago, niceDate} from 'lib/strings/time'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
import {pluralize} from 'lib/strings/helpers'
|
||||
import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers'
|
||||
import {useStores} from 'state/index'
|
||||
import {PostMeta} from '../util/PostMeta'
|
||||
import {PostEmbeds} from '../util/post-embeds'
|
||||
|
@ -65,6 +66,13 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
}, [item.post.uri, item.post.author.handle])
|
||||
const repostsTitle = 'Reposts of this post'
|
||||
|
||||
const primaryLanguage = store.preferences.contentLanguages[0] || 'en'
|
||||
const translatorUrl = getTranslatorLink(primaryLanguage, record?.text || '')
|
||||
const needsTranslation = useMemo(
|
||||
() => !isPostInLanguage(item.post, store.preferences.contentLanguages),
|
||||
[item.post, store.preferences.contentLanguages],
|
||||
)
|
||||
|
||||
const onPressReply = React.useCallback(() => {
|
||||
store.shell.openComposer({
|
||||
replyTo: {
|
||||
|
@ -98,17 +106,9 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
Toast.show('Copied to clipboard')
|
||||
}, [record])
|
||||
|
||||
const primaryLanguage = store.preferences.contentLanguages[0] || 'en'
|
||||
|
||||
const onOpenTranslate = React.useCallback(() => {
|
||||
Linking.openURL(
|
||||
encodeURI(
|
||||
`https://translate.google.com/?sl=auto&tl=${primaryLanguage}&text=${
|
||||
record?.text || ''
|
||||
}`,
|
||||
),
|
||||
)
|
||||
}, [record, primaryLanguage])
|
||||
Linking.openURL(translatorUrl)
|
||||
}, [translatorUrl])
|
||||
|
||||
const onToggleThreadMute = React.useCallback(async () => {
|
||||
try {
|
||||
|
@ -276,6 +276,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
type="post-text-lg"
|
||||
richText={item.richText}
|
||||
lineHeight={1.3}
|
||||
style={s.flex1}
|
||||
/>
|
||||
</View>
|
||||
) : undefined}
|
||||
|
@ -283,9 +284,11 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
<PostEmbeds embed={item.post.embed} style={s.mb10} />
|
||||
</ImageHider>
|
||||
</ContentHider>
|
||||
<View style={[s.mt2, s.mb10]}>
|
||||
<Text style={pal.textLight}>{niceDate(item.post.indexedAt)}</Text>
|
||||
</View>
|
||||
<ExpandedPostDetails
|
||||
post={item.post}
|
||||
translatorUrl={translatorUrl}
|
||||
needsTranslation={needsTranslation}
|
||||
/>
|
||||
{hasEngagement ? (
|
||||
<View style={[styles.expandedInfo, pal.border]}>
|
||||
{item.post.repostCount ? (
|
||||
|
@ -411,7 +414,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
<RichText
|
||||
type="post-text"
|
||||
richText={item.richText}
|
||||
style={pal.text}
|
||||
style={[pal.text, s.flex1]}
|
||||
lineHeight={1.3}
|
||||
/>
|
||||
</View>
|
||||
|
@ -419,6 +422,15 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
<ImageHider style={s.mb10} moderation={item.moderation.thread}>
|
||||
<PostEmbeds embed={item.post.embed} style={s.mb10} />
|
||||
</ImageHider>
|
||||
{needsTranslation && (
|
||||
<View style={[pal.borderDark, styles.translateLink]}>
|
||||
<Link href={translatorUrl} title="Translate">
|
||||
<Text type="sm" style={pal.link}>
|
||||
Translate this post
|
||||
</Text>
|
||||
</Link>
|
||||
</View>
|
||||
)}
|
||||
</ContentHider>
|
||||
<PostCtrls
|
||||
itemUri={itemUri}
|
||||
|
@ -473,6 +485,31 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
}
|
||||
})
|
||||
|
||||
function ExpandedPostDetails({
|
||||
post,
|
||||
needsTranslation,
|
||||
translatorUrl,
|
||||
}: {
|
||||
post: AppBskyFeedDefs.PostView
|
||||
needsTranslation: boolean
|
||||
translatorUrl: string
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<View style={[s.flexRow, s.mt2, s.mb10]}>
|
||||
<Text style={pal.textLight}>{niceDate(post.indexedAt)}</Text>
|
||||
{needsTranslation && (
|
||||
<>
|
||||
<Text style={pal.textLight}> • </Text>
|
||||
<Link href={translatorUrl} title="Translate">
|
||||
<Text style={pal.link}>Translate</Text>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
outer: {
|
||||
borderTopWidth: 1,
|
||||
|
@ -540,6 +577,9 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 0,
|
||||
paddingBottom: 10,
|
||||
},
|
||||
translateLink: {
|
||||
marginBottom: 6,
|
||||
},
|
||||
contentHider: {
|
||||
marginTop: 4,
|
||||
},
|
||||
|
|
|
@ -30,6 +30,7 @@ import {UserAvatar} from '../util/UserAvatar'
|
|||
import {useStores} from 'state/index'
|
||||
import {s, colors} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {getTranslatorLink} from '../../../locale/helpers'
|
||||
|
||||
export const Post = observer(function Post({
|
||||
uri,
|
||||
|
@ -167,16 +168,11 @@ const PostLoaded = observer(
|
|||
}, [record])
|
||||
|
||||
const primaryLanguage = store.preferences.contentLanguages[0] || 'en'
|
||||
const translatorUrl = getTranslatorLink(primaryLanguage, record?.text || '')
|
||||
|
||||
const onOpenTranslate = React.useCallback(() => {
|
||||
Linking.openURL(
|
||||
encodeURI(
|
||||
`https://translate.google.com/?sl=auto&tl=${primaryLanguage}&text=${
|
||||
record?.text || ''
|
||||
}`,
|
||||
),
|
||||
)
|
||||
}, [record, primaryLanguage])
|
||||
Linking.openURL(translatorUrl)
|
||||
}, [translatorUrl])
|
||||
|
||||
const onToggleThreadMute = React.useCallback(async () => {
|
||||
try {
|
||||
|
@ -299,6 +295,7 @@ const PostLoaded = observer(
|
|||
type="post-text"
|
||||
richText={item.richText}
|
||||
lineHeight={1.3}
|
||||
style={s.flex1}
|
||||
/>
|
||||
</View>
|
||||
) : undefined}
|
||||
|
|
|
@ -27,6 +27,7 @@ import {useStores} from 'state/index'
|
|||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers'
|
||||
|
||||
export const FeedItem = observer(function ({
|
||||
item,
|
||||
|
@ -62,6 +63,12 @@ export const FeedItem = observer(function ({
|
|||
const urip = new AtUri(record.reply.parent?.uri || record.reply.root.uri)
|
||||
return urip.hostname
|
||||
}, [record?.reply])
|
||||
const primaryLanguage = store.preferences.contentLanguages[0] || 'en'
|
||||
const translatorUrl = getTranslatorLink(primaryLanguage, record?.text || '')
|
||||
const needsTranslation = useMemo(
|
||||
() => !isPostInLanguage(item.post, store.preferences.contentLanguages),
|
||||
[item.post, store.preferences.contentLanguages],
|
||||
)
|
||||
|
||||
const onPressReply = React.useCallback(() => {
|
||||
track('FeedItem:PostReply')
|
||||
|
@ -98,17 +105,9 @@ export const FeedItem = observer(function ({
|
|||
Toast.show('Copied to clipboard')
|
||||
}, [record])
|
||||
|
||||
const primaryLanguage = store.preferences.contentLanguages[0] || 'en'
|
||||
|
||||
const onOpenTranslate = React.useCallback(() => {
|
||||
Linking.openURL(
|
||||
encodeURI(
|
||||
`https://translate.google.com/?sl=auto&tl=${primaryLanguage}&text=${
|
||||
record?.text || ''
|
||||
}`,
|
||||
),
|
||||
)
|
||||
}, [record, primaryLanguage])
|
||||
Linking.openURL(translatorUrl)
|
||||
}, [translatorUrl])
|
||||
|
||||
const onToggleThreadMute = React.useCallback(async () => {
|
||||
track('FeedItem:ThreadMute')
|
||||
|
@ -301,12 +300,22 @@ export const FeedItem = observer(function ({
|
|||
type="post-text"
|
||||
richText={item.richText}
|
||||
lineHeight={1.3}
|
||||
style={s.flex1}
|
||||
/>
|
||||
</View>
|
||||
) : undefined}
|
||||
<ImageHider moderation={item.moderation.list} style={styles.embed}>
|
||||
<PostEmbeds embed={item.post.embed} style={styles.embed} />
|
||||
</ImageHider>
|
||||
{needsTranslation && (
|
||||
<View style={[pal.borderDark, styles.translateLink]}>
|
||||
<Link href={translatorUrl} title="Translate">
|
||||
<Text type="sm" style={pal.link}>
|
||||
Translate this post
|
||||
</Text>
|
||||
</Link>
|
||||
</View>
|
||||
)}
|
||||
</ContentHider>
|
||||
<PostCtrls
|
||||
style={styles.ctrls}
|
||||
|
@ -402,6 +411,9 @@ const styles = StyleSheet.create({
|
|||
embed: {
|
||||
marginBottom: 6,
|
||||
},
|
||||
translateLink: {
|
||||
marginBottom: 6,
|
||||
},
|
||||
ctrls: {
|
||||
marginTop: 4,
|
||||
},
|
||||
|
|
|
@ -609,6 +609,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
|
||||
description: {
|
||||
flex: 1,
|
||||
marginBottom: 8,
|
||||
},
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue