Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve notification localization #5550

Merged
merged 4 commits into from
Oct 31, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
229 changes: 168 additions & 61 deletions src/view/com/notifications/FeedItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, {memo, useEffect, useMemo, useState} from 'react'
import React, {
memo,
type ReactElement,
useEffect,
useMemo,
useState,
} from 'react'
import {
Animated,
Pressable,
Expand All @@ -17,7 +23,7 @@ import {
} from '@atproto/api'
import {AtUri} from '@atproto/api'
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 {useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query'
Expand Down Expand Up @@ -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 = (
<HeartIconFilled
size="xl"
Expand All @@ -177,10 +208,55 @@ let FeedItem = ({
]}
/>
)

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') {
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}} />
} else if (item.type === 'follow') {
let isFollowBack = false
Expand All @@ -204,40 +280,96 @@ let FeedItem = ({
}
}

if (isFollowBack) {
action = _(msg`followed you back`)
if (isFollowBack && !hasMultipleAuthors) {
/*
* 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 {
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}} />
} 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') {
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 = (
<View style={{height: 30, width: 30}}>
<StarterPack width={30} gradient="sky" />
</View>
)
action = _(msg`signed up with your starter pack`)
} else {
return null
}

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}`
a11yLabel += ` · ${niceTimestamp}`

return (
<Link
Expand All @@ -260,7 +392,7 @@ let FeedItem = ({
accessibilityLabel={a11yLabel}
accessible={!isAuthorsExpanded}
accessibilityActions={
authors.length > 1
hasMultipleAuthors
? [
{
name: 'toggleAuthorsExpanded',
Expand Down Expand Up @@ -288,7 +420,6 @@ let FeedItem = ({
onToggleAuthorsExpanded()
}
}}
onBeforePress={onBeforePress}
onPointerEnter={() => {
setHover(true)
}}
Expand All @@ -303,7 +434,7 @@ let FeedItem = ({
</View>
<View style={styles.layoutContent}>
<ExpandListPressable
hasMultipleAuthors={authors.length > 1}
hasMultipleAuthors={hasMultipleAuthors}
onToggleAuthorsExpanded={onToggleAuthorsExpanded}>
<CondensedAuthorsList
visible={!isAuthorsExpanded}
Expand All @@ -313,42 +444,18 @@ let FeedItem = ({
/>
<ExpandedAuthorsList visible={isAuthorsExpanded} authors={authors} />
<Text
style={[styles.meta, a.self_start]}
style={[styles.meta, a.self_start, pal.text]}
accessibilityHint=""
accessibilityLabel={a11yLabel}>
<TextLink
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>
{notificationContent}
<TimeElapsed timestamp={item.notification.indexedAt}>
{({timeElapsed}) => (
<Text
style={[pal.textLight, styles.pointer]}
title={niceTimestamp}>
{' ' + timeElapsed}
</Text>
<>
<Text style={[a.ml_xs, pal.textLight]}>&middot;</Text>
<Text style={[a.ml_xs, pal.textLight]} title={niceTimestamp}>
{timeElapsed}
</Text>
</>
)}
</TimeElapsed>
</Text>
Expand Down
Loading