Improve notification localization (#5550)
* Improve notification localization (#3911) * Update FeedItem.tsx * Update FeedItem.tsx * Update FeedItem.tsx * Update FeedItem.tsx * Update FeedItem.tsx * Update FeedItem.tsx * Update FeedItem.tsx * Update FeedItem.tsx * Update FeedItem.tsx * Update PostMeta.tsx * Update RightNav.tsx * Update FeedItem.tsx * Update FeedItem.tsx * a11y * Update FeedItem.tsx * Update PostThreadItem.tsx * Update PostThreadItem.tsx * revert * Update FeedItem.tsx * Update FeedItem.tsx * Update FeedItem.tsx * Revert "Merge remote-tracking branch 'upstream/main' into Improve-notification-localization" This reverts commitf435d1e7ed, reversing changes made todae2aee676. * Reapply "Merge remote-tracking branch 'upstream/main' into Improve-notification-localization" This reverts commitc93ac19048. * Update ThreadgateBtn.tsx * Rm import edits for now * Cleanups --------- Co-authored-by: Minseo Lee <itoupluk427@gmail.com>
This commit is contained in:
@@ -1,4 +1,10 @@
|
|||||||
import React, {memo, useEffect, useMemo, useState} from 'react'
|
import React, {
|
||||||
|
memo,
|
||||||
|
type ReactElement,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from 'react'
|
||||||
import {
|
import {
|
||||||
Animated,
|
Animated,
|
||||||
Pressable,
|
Pressable,
|
||||||
@@ -17,7 +23,7 @@ import {
|
|||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {AtUri} from '@atproto/api'
|
import {AtUri} from '@atproto/api'
|
||||||
import {TID} from '@atproto/common-web'
|
import {TID} from '@atproto/common-web'
|
||||||
import {msg, plural, Trans} from '@lingui/macro'
|
import {msg, Plural, plural, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
@@ -167,7 +173,32 @@ let FeedItem = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = ''
|
const niceTimestamp = niceDate(i18n, item.notification.indexedAt)
|
||||||
|
const firstAuthor = authors[0]
|
||||||
|
const firstAuthorName = sanitizeDisplayName(
|
||||||
|
firstAuthor.profile.displayName || firstAuthor.profile.handle,
|
||||||
|
)
|
||||||
|
const firstAuthorLink = (
|
||||||
|
<TextLink
|
||||||
|
key={firstAuthor.href}
|
||||||
|
style={[pal.text, s.bold]}
|
||||||
|
href={firstAuthor.href}
|
||||||
|
text={
|
||||||
|
<Text emoji style={[pal.text, s.bold]}>
|
||||||
|
{forceLTR(firstAuthorName)}
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
|
disableMismatchWarning
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
const additionalAuthorsCount = authors.length - 1
|
||||||
|
const hasMultipleAuthors = additionalAuthorsCount > 0
|
||||||
|
const formattedAuthorsCount = hasMultipleAuthors
|
||||||
|
? formatCount(i18n, additionalAuthorsCount)
|
||||||
|
: ''
|
||||||
|
|
||||||
|
let a11yLabel = ''
|
||||||
|
let notificationContent: ReactElement
|
||||||
let icon = (
|
let icon = (
|
||||||
<HeartIconFilled
|
<HeartIconFilled
|
||||||
size="xl"
|
size="xl"
|
||||||
@@ -177,10 +208,55 @@ let FeedItem = ({
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
if (item.type === 'post-like') {
|
if (item.type === 'post-like') {
|
||||||
action = _(msg`liked your post`)
|
a11yLabel = hasMultipleAuthors
|
||||||
|
? _(
|
||||||
|
msg`${firstAuthorName} and ${plural(additionalAuthorsCount, {
|
||||||
|
one: `${formattedAuthorsCount} other`,
|
||||||
|
other: `${formattedAuthorsCount} others`,
|
||||||
|
})} liked your post`,
|
||||||
|
)
|
||||||
|
: _(msg`${firstAuthorName} liked your post`)
|
||||||
|
notificationContent = hasMultipleAuthors ? (
|
||||||
|
<Trans>
|
||||||
|
{firstAuthorLink} and{' '}
|
||||||
|
<Text style={[pal.text, s.bold]}>
|
||||||
|
<Plural
|
||||||
|
value={additionalAuthorsCount}
|
||||||
|
one={`${formattedAuthorsCount} other`}
|
||||||
|
other={`${formattedAuthorsCount} others`}
|
||||||
|
/>
|
||||||
|
</Text>{' '}
|
||||||
|
liked your post
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>{firstAuthorLink} liked your post</Trans>
|
||||||
|
)
|
||||||
} else if (item.type === 'repost') {
|
} else if (item.type === 'repost') {
|
||||||
action = _(msg`reposted your post`)
|
a11yLabel = hasMultipleAuthors
|
||||||
|
? _(
|
||||||
|
msg`${firstAuthorName} and ${plural(additionalAuthorsCount, {
|
||||||
|
one: `${formattedAuthorsCount} other`,
|
||||||
|
other: `${formattedAuthorsCount} others`,
|
||||||
|
})} reposted your post`,
|
||||||
|
)
|
||||||
|
: _(msg`${firstAuthorName} reposted your post`)
|
||||||
|
notificationContent = hasMultipleAuthors ? (
|
||||||
|
<Trans>
|
||||||
|
{firstAuthorLink} and{' '}
|
||||||
|
<Text style={[pal.text, s.bold]}>
|
||||||
|
<Plural
|
||||||
|
value={additionalAuthorsCount}
|
||||||
|
one={`${formattedAuthorsCount} other`}
|
||||||
|
other={`${formattedAuthorsCount} others`}
|
||||||
|
/>
|
||||||
|
</Text>{' '}
|
||||||
|
reposted your post
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>{firstAuthorLink} reposted your post</Trans>
|
||||||
|
)
|
||||||
icon = <RepostIcon size="xl" style={{color: t.palette.positive_600}} />
|
icon = <RepostIcon size="xl" style={{color: t.palette.positive_600}} />
|
||||||
} else if (item.type === 'follow') {
|
} else if (item.type === 'follow') {
|
||||||
let isFollowBack = false
|
let isFollowBack = false
|
||||||
@@ -204,40 +280,96 @@ let FeedItem = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFollowBack) {
|
if (isFollowBack && !hasMultipleAuthors) {
|
||||||
action = _(msg`followed you back`)
|
/*
|
||||||
|
* Follow-backs are ungrouped, grouped follow-backs not supported atm,
|
||||||
|
* see `src/state/queries/notifications/util.ts`
|
||||||
|
*/
|
||||||
|
a11yLabel = _(msg`${firstAuthorName} followed you back`)
|
||||||
|
notificationContent = <Trans>{firstAuthorLink} followed you back</Trans>
|
||||||
} else {
|
} else {
|
||||||
action = _(msg`followed you`)
|
a11yLabel = hasMultipleAuthors
|
||||||
|
? _(
|
||||||
|
msg`${firstAuthorName} and ${plural(additionalAuthorsCount, {
|
||||||
|
one: `${formattedAuthorsCount} other`,
|
||||||
|
other: `${formattedAuthorsCount} others`,
|
||||||
|
})} followed you`,
|
||||||
|
)
|
||||||
|
: _(msg`${firstAuthorName} followed you`)
|
||||||
|
notificationContent = hasMultipleAuthors ? (
|
||||||
|
<Trans>
|
||||||
|
{firstAuthorLink} and{' '}
|
||||||
|
<Text style={[pal.text, s.bold]}>
|
||||||
|
<Plural
|
||||||
|
value={additionalAuthorsCount}
|
||||||
|
one={`${formattedAuthorsCount} other`}
|
||||||
|
other={`${formattedAuthorsCount} others`}
|
||||||
|
/>
|
||||||
|
</Text>{' '}
|
||||||
|
followed you
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>{firstAuthorLink} followed you</Trans>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
icon = <PersonPlusIcon size="xl" style={{color: t.palette.primary_500}} />
|
icon = <PersonPlusIcon size="xl" style={{color: t.palette.primary_500}} />
|
||||||
} else if (item.type === 'feedgen-like') {
|
} else if (item.type === 'feedgen-like') {
|
||||||
action = _(msg`liked your custom feed`)
|
a11yLabel = hasMultipleAuthors
|
||||||
|
? _(
|
||||||
|
msg`${firstAuthorName} and ${plural(additionalAuthorsCount, {
|
||||||
|
one: `${formattedAuthorsCount} other`,
|
||||||
|
other: `${formattedAuthorsCount} others`,
|
||||||
|
})} liked your custom feed`,
|
||||||
|
)
|
||||||
|
: _(msg`${firstAuthorName} liked your custom feed`)
|
||||||
|
notificationContent = hasMultipleAuthors ? (
|
||||||
|
<Trans>
|
||||||
|
{firstAuthorLink} and{' '}
|
||||||
|
<Text style={[pal.text, s.bold]}>
|
||||||
|
<Plural
|
||||||
|
value={additionalAuthorsCount}
|
||||||
|
one={`${formattedAuthorsCount} other`}
|
||||||
|
other={`${formattedAuthorsCount} others`}
|
||||||
|
/>
|
||||||
|
</Text>{' '}
|
||||||
|
liked your custom feed
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>{firstAuthorLink} liked your custom feed</Trans>
|
||||||
|
)
|
||||||
} else if (item.type === 'starterpack-joined') {
|
} else if (item.type === 'starterpack-joined') {
|
||||||
|
a11yLabel = hasMultipleAuthors
|
||||||
|
? _(
|
||||||
|
msg`${firstAuthorName} and ${plural(additionalAuthorsCount, {
|
||||||
|
one: `${formattedAuthorsCount} other`,
|
||||||
|
other: `${formattedAuthorsCount} others`,
|
||||||
|
})} signed up with your starter pack`,
|
||||||
|
)
|
||||||
|
: _(msg`${firstAuthorName} signed up with your starter pack`)
|
||||||
|
notificationContent = hasMultipleAuthors ? (
|
||||||
|
<Trans>
|
||||||
|
{firstAuthorLink} and{' '}
|
||||||
|
<Text style={[pal.text, s.bold]}>
|
||||||
|
<Plural
|
||||||
|
value={additionalAuthorsCount}
|
||||||
|
one={`${formattedAuthorsCount} other`}
|
||||||
|
other={`${formattedAuthorsCount} others`}
|
||||||
|
/>
|
||||||
|
</Text>{' '}
|
||||||
|
signed up with your starter pack
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>{firstAuthorLink} signed up with your starter pack</Trans>
|
||||||
|
)
|
||||||
icon = (
|
icon = (
|
||||||
<View style={{height: 30, width: 30}}>
|
<View style={{height: 30, width: 30}}>
|
||||||
<StarterPack width={30} gradient="sky" />
|
<StarterPack width={30} gradient="sky" />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
action = _(msg`signed up with your starter pack`)
|
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
a11yLabel += ` · ${niceTimestamp}`
|
||||||
const formattedCount =
|
|
||||||
authors.length > 1 ? formatCount(i18n, authors.length - 1) : ''
|
|
||||||
const firstAuthorName = sanitizeDisplayName(
|
|
||||||
authors[0].profile.displayName || authors[0].profile.handle,
|
|
||||||
)
|
|
||||||
const niceTimestamp = niceDate(i18n, item.notification.indexedAt)
|
|
||||||
const a11yLabelUsers =
|
|
||||||
authors.length > 1
|
|
||||||
? _(msg` and `) +
|
|
||||||
plural(authors.length - 1, {
|
|
||||||
one: `${formattedCount} other`,
|
|
||||||
other: `${formattedCount} others`,
|
|
||||||
})
|
|
||||||
: ''
|
|
||||||
const a11yLabel = `${firstAuthorName}${a11yLabelUsers} ${action} ${niceTimestamp}`
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
@@ -260,7 +392,7 @@ let FeedItem = ({
|
|||||||
accessibilityLabel={a11yLabel}
|
accessibilityLabel={a11yLabel}
|
||||||
accessible={!isAuthorsExpanded}
|
accessible={!isAuthorsExpanded}
|
||||||
accessibilityActions={
|
accessibilityActions={
|
||||||
authors.length > 1
|
hasMultipleAuthors
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
name: 'toggleAuthorsExpanded',
|
name: 'toggleAuthorsExpanded',
|
||||||
@@ -288,7 +420,6 @@ let FeedItem = ({
|
|||||||
onToggleAuthorsExpanded()
|
onToggleAuthorsExpanded()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onBeforePress={onBeforePress}
|
|
||||||
onPointerEnter={() => {
|
onPointerEnter={() => {
|
||||||
setHover(true)
|
setHover(true)
|
||||||
}}
|
}}
|
||||||
@@ -303,7 +434,7 @@ let FeedItem = ({
|
|||||||
</View>
|
</View>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
<ExpandListPressable
|
<ExpandListPressable
|
||||||
hasMultipleAuthors={authors.length > 1}
|
hasMultipleAuthors={hasMultipleAuthors}
|
||||||
onToggleAuthorsExpanded={onToggleAuthorsExpanded}>
|
onToggleAuthorsExpanded={onToggleAuthorsExpanded}>
|
||||||
<CondensedAuthorsList
|
<CondensedAuthorsList
|
||||||
visible={!isAuthorsExpanded}
|
visible={!isAuthorsExpanded}
|
||||||
@@ -313,42 +444,18 @@ let FeedItem = ({
|
|||||||
/>
|
/>
|
||||||
<ExpandedAuthorsList visible={isAuthorsExpanded} authors={authors} />
|
<ExpandedAuthorsList visible={isAuthorsExpanded} authors={authors} />
|
||||||
<Text
|
<Text
|
||||||
style={[styles.meta, a.self_start]}
|
style={[styles.meta, a.self_start, pal.text]}
|
||||||
accessibilityHint=""
|
accessibilityHint=""
|
||||||
accessibilityLabel={a11yLabel}>
|
accessibilityLabel={a11yLabel}>
|
||||||
<TextLink
|
{notificationContent}
|
||||||
key={authors[0].href}
|
|
||||||
style={[pal.text, s.bold]}
|
|
||||||
href={authors[0].href}
|
|
||||||
text={
|
|
||||||
<Text emoji style={[pal.text, s.bold]}>
|
|
||||||
{forceLTR(firstAuthorName)}
|
|
||||||
</Text>
|
|
||||||
}
|
|
||||||
disableMismatchWarning
|
|
||||||
/>
|
|
||||||
{authors.length > 1 ? (
|
|
||||||
<>
|
|
||||||
<Text style={[pal.text]}>
|
|
||||||
{' '}
|
|
||||||
<Trans>and</Trans>{' '}
|
|
||||||
</Text>
|
|
||||||
<Text style={[pal.text, s.bold]}>
|
|
||||||
{plural(authors.length - 1, {
|
|
||||||
one: `${formattedCount} other`,
|
|
||||||
other: `${formattedCount} others`,
|
|
||||||
})}
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
) : undefined}
|
|
||||||
<Text style={[pal.text]}> {action}</Text>
|
|
||||||
<TimeElapsed timestamp={item.notification.indexedAt}>
|
<TimeElapsed timestamp={item.notification.indexedAt}>
|
||||||
{({timeElapsed}) => (
|
{({timeElapsed}) => (
|
||||||
<Text
|
<>
|
||||||
style={[pal.textLight, styles.pointer]}
|
<Text style={[a.ml_xs, pal.textLight]}>·</Text>
|
||||||
title={niceTimestamp}>
|
<Text style={[a.ml_xs, pal.textLight]} title={niceTimestamp}>
|
||||||
{' ' + timeElapsed}
|
{timeElapsed}
|
||||||
</Text>
|
</Text>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</TimeElapsed>
|
</TimeElapsed>
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
Reference in New Issue
Block a user