2
2
mirror of https://github.com/mastodon/mastodon-ios synced 2025-04-11 22:58:02 +02:00

Add localizations for grouped notifications

Contributes to #399 [BUG] Multiple interactions do not collapse into a single notification
This commit is contained in:
shannon 2025-03-03 08:06:26 -05:00
parent 1a2f02e589
commit 725a004f33
6 changed files with 160 additions and 49 deletions

View File

@ -734,6 +734,20 @@
"Everything": "Everything",
"Mentions": "Mentions"
},
"grouped_notification_description": {
"your_poll_has_ended": "Your poll has ended",
"single_name_ran_poll": "%@ ran %@",
"single_name_mentioned_you": "%@ mentioned you",
"single_name_requested_to_follow_you": "%@ requested to follow you",
"single_name_posted": "%@ posted:",
"single_name_boosted": "%@ boosted:",
"single_name_favourited": "%@ favourited:",
"single_name_followed_you": "%@ followed you",
"multiple_people_boosted": "%@ boosted:",
"multiple_people_favourited": "%@ favourited:",
"multiple_people_followed_you": "%@ followed you",
"single_name_signed_up": "%@ signed up"
},
"notification_description": {
"followed_you": "followed you",
"favorited_your_post": "favorited your post",

View File

@ -113,76 +113,60 @@ extension GroupedNotificationType {
{
guard let authorName = sourceAccounts.authorName else { return nil }
let totalAuthorCount = sourceAccounts.totalActorCount
// TODO: L10n strings
switch authorName {
case .me:
assert(totalAuthorCount == 1)
//assert(self == .poll)
return "Your poll has ended"
return AttributedString(L10n.Scene.Notification.GroupedNotificationDescription.yourPollHasEnded)
case .other(let firstAuthorName):
let nameComponent = boldedNameStringComponent(firstAuthorName)
var composedString: AttributedString
var plainString: String
if totalAuthorCount == 1 {
switch self {
case .favourite:
composedString =
nameComponent + AttributedString(" favorited:")
plainString = L10n.Scene.Notification.GroupedNotificationDescription.singleNameFavourited(firstAuthorName)
case .follow:
composedString =
nameComponent + AttributedString(" followed you")
plainString = L10n.Scene.Notification.GroupedNotificationDescription.singleNameFollowedYou(firstAuthorName)
case .followRequest:
composedString =
nameComponent
+ AttributedString(" requested to follow you")
plainString = L10n.Scene.Notification.GroupedNotificationDescription.singleNameRequestedToFollowYou(firstAuthorName)
case .reblog:
composedString =
nameComponent + AttributedString(" boosted:")
plainString = L10n.Scene.Notification.GroupedNotificationDescription.singleNameBoosted(firstAuthorName)
case .mention:
composedString =
nameComponent + AttributedString(" mentioned you:")
case .poll:
composedString =
nameComponent
+ AttributedString(" ran a poll that you voted in") // TODO: add count of how many others voted
plainString = L10n.Scene.Notification.GroupedNotificationDescription.singleNameMentionedYou(firstAuthorName)
case .poll(let status):
let votersCount = status?.poll?.votersCount ?? 0
let pollDescription = L10n.Plural.Count.pollThatYouAndOthersVotedIn(votersCount)
plainString = L10n.Scene.Notification.GroupedNotificationDescription.singleNameRanPoll(firstAuthorName, pollDescription)
case .status:
composedString =
nameComponent + AttributedString(" posted:")
plainString = L10n.Scene.Notification.GroupedNotificationDescription.singleNamePosted(firstAuthorName)
case .adminSignUp:
composedString =
nameComponent + AttributedString(" signed up")
plainString = L10n.Scene.Notification.GroupedNotificationDescription.singleNameSignedUp(firstAuthorName)
default:
composedString =
nameComponent + AttributedString("did something?")
plainString = "\(firstAuthorName) did something"
}
} else {
let actorsList = sourceAccounts.authorsDescription ?? firstAuthorName
switch self {
case .favourite:
composedString =
nameComponent
+ AttributedString(
" and \(totalAuthorCount - 1) others favorited:")
plainString = L10n.Scene.Notification.GroupedNotificationDescription.multiplePeopleFavourited(actorsList)
case .follow:
composedString =
nameComponent
+ AttributedString(
" and \(totalAuthorCount - 1) others followed you")
plainString = L10n.Scene.Notification.GroupedNotificationDescription.multiplePeopleFollowedYou(actorsList)
case .reblog:
composedString =
nameComponent
+ AttributedString(
" and \(totalAuthorCount - 1) others boosted:")
plainString = L10n.Scene.Notification.GroupedNotificationDescription.multiplePeopleBoosted(actorsList)
default:
composedString =
nameComponent
+ AttributedString(
" and \(totalAuthorCount - 1) others did something")
plainString = "\(actorsList) did something"
}
}
let nameStyling = AttributeContainer.font(
.system(.body, weight: .bold))
let nameContainer = AttributeContainer.personNameComponent(
.givenName)
composedString.replaceAttributes(nameContainer, with: nameStyling)
var composedString = AttributedString(plainString)
if let range = composedString.range(of: firstAuthorName) {
let authorNameComponent = stylableNameComponent(firstAuthorName)
composedString.replaceSubrange(range, with: authorNameComponent)
let nameStyling = AttributeContainer.font(
.system(.body, weight: .bold))
let nameContainer = AttributeContainer.personNameComponent(
.givenName)
composedString.replaceAttributes(nameContainer, with: nameStyling)
}
return composedString
}
}
@ -193,7 +177,7 @@ extension Mastodon.Entity.Report {
// "Someone reported X posts from someone else for rule violation"
var summary: AttributedString {
if let targetedAccountName = targetAccount?.displayNameWithFallback {
let boldedName = boldedNameStringComponent(targetedAccountName)
let boldedName = stylableNameComponent(targetedAccountName)
if let postCount = flaggedStatusIDs?.count {
return AttributedString(
"Someone reported \(postCount) posts from ") + boldedName
@ -778,7 +762,7 @@ enum NotificationViewComponent: Identifiable {
}
}
func boldedNameStringComponent(_ name: String) -> AttributedString {
func stylableNameComponent(_ name: String) -> AttributedString {
let nameComponent = PersonNameComponents(givenName: name).formatted(
.name(style: .long).attributed)
return nameComponent

View File

@ -755,7 +755,8 @@ extension NotificationSourceAccounts {
return nil
case .other(let name):
if totalActorCount > 1 {
return "\(name) and \(totalActorCount - 1) others"
let formatter = ListFormatter()
return formatter.string(from: [name, L10n.Plural.Count.others(totalActorCount - 1)])
} else {
return name
}

View File

@ -957,6 +957,54 @@ public enum L10n {
/// Rejected
public static let rejected = L10n.tr("Localizable", "Scene.Notification.FollowRequest.Rejected", fallback: "Rejected")
}
public enum GroupedNotificationDescription {
/// %@ boosted:
public static func multiplePeopleBoosted(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.MultiplePeopleBoosted", String(describing: p1), fallback: "%@ boosted:")
}
/// %@ favourited:
public static func multiplePeopleFavourited(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.MultiplePeopleFavourited", String(describing: p1), fallback: "%@ favourited:")
}
/// %@ followed you
public static func multiplePeopleFollowedYou(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.MultiplePeopleFollowedYou", String(describing: p1), fallback: "%@ followed you")
}
/// %@ boosted:
public static func singleNameBoosted(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.SingleNameBoosted", String(describing: p1), fallback: "%@ boosted:")
}
/// %@ favourited:
public static func singleNameFavourited(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.SingleNameFavourited", String(describing: p1), fallback: "%@ favourited:")
}
/// %@ followed you
public static func singleNameFollowedYou(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.SingleNameFollowedYou", String(describing: p1), fallback: "%@ followed you")
}
/// %@ mentioned you
public static func singleNameMentionedYou(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.SingleNameMentionedYou", String(describing: p1), fallback: "%@ mentioned you")
}
/// %@ posted:
public static func singleNamePosted(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.SingleNamePosted", String(describing: p1), fallback: "%@ posted:")
}
/// %@ ran %@
public static func singleNameRanPoll(_ p1: Any, _ p2: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.SingleNameRanPoll", String(describing: p1), String(describing: p2), fallback: "%@ ran %@")
}
/// %@ requested to follow you
public static func singleNameRequestedToFollowYou(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.SingleNameRequestedToFollowYou", String(describing: p1), fallback: "%@ requested to follow you")
}
/// %@ signed up
public static func singleNameSignedUp(_ p1: Any) -> String {
return L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.SingleNameSignedUp", String(describing: p1), fallback: "%@ signed up")
}
/// Your poll has ended
public static let yourPollHasEnded = L10n.tr("Localizable", "Scene.Notification.GroupedNotificationDescription.YourPollHasEnded", fallback: "Your poll has ended")
}
public enum Keyobard {
/// Show Everything
public static let showEverything = L10n.tr("Localizable", "Scene.Notification.Keyobard.ShowEverything", fallback: "Show Everything")
@ -2029,10 +2077,18 @@ public enum L10n {
public static func ofYourFollowers(_ p1: Int) -> String {
return L10n.tr("Localizable", "plural.count.of_your_followers", p1, fallback: "Plural format key: \"%#@count_of_your_followers@\"")
}
/// Plural format key: "%#@count_others@"
public static func others(_ p1: Int) -> String {
return L10n.tr("Localizable", "plural.count.others", p1, fallback: "Plural format key: \"%#@count_others@\"")
}
/// Plural format key: "%#@poll_count@"
public static func poll(_ p1: Int) -> String {
return L10n.tr("Localizable", "plural.count.poll", p1, fallback: "Plural format key: \"%#@poll_count@\"")
}
/// Plural format key: "%#@count_others@"
public static func pollThatYouAndOthersVotedIn(_ p1: Int) -> String {
return L10n.tr("Localizable", "plural.count.poll_that_you_and_others_voted_in", p1, fallback: "Plural format key: \"%#@count_others@\"")
}
/// Plural format key: "%#@post_count@"
public static func post(_ p1: Int) -> String {
return L10n.tr("Localizable", "plural.count.post", p1, fallback: "Plural format key: \"%#@post_count@\"")

View File

@ -343,6 +343,18 @@ Please retry in a few minutes.";
"Scene.Notification.FollowRequest.Rejected" = "Rejected";
"Scene.Notification.Keyobard.ShowEverything" = "Show Everything";
"Scene.Notification.Keyobard.ShowMentions" = "Show Mentions";
"Scene.Notification.GroupedNotificationDescription.YourPollHasEnded" = "Your poll has ended";
"Scene.Notification.GroupedNotificationDescription.SingleNameMentionedYou" = "%@ mentioned you";
"Scene.Notification.GroupedNotificationDescription.SingleNameRequestedToFollowYou" = "%@ requested to follow you";
"Scene.Notification.GroupedNotificationDescription.SingleNamePosted" = "%@ posted:";
"Scene.Notification.GroupedNotificationDescription.SingleNameBoosted" = "%@ boosted:";
"Scene.Notification.GroupedNotificationDescription.SingleNameFavourited" = "%@ favourited:";
"Scene.Notification.GroupedNotificationDescription.SingleNameFollowedYou" = "%@ followed you";
"Scene.Notification.GroupedNotificationDescription.SingleNameRanPoll" = "%@ ran %@";
"Scene.Notification.GroupedNotificationDescription.MultiplePeopleBoosted" = "%@ boosted:";
"Scene.Notification.GroupedNotificationDescription.MultiplePeopleFavourited" = "%@ favourited:";
"Scene.Notification.GroupedNotificationDescription.MultiplePeopleFollowedYou" = "%@ followed you";
"Scene.Notification.GroupedNotificationDescription.SingleNameSignedUp" = "%@ signed up";
"Scene.Notification.NotificationDescription.FavoritedYourPost" = "favorited your post";
"Scene.Notification.NotificationDescription.FollowedYou" = "followed you";
"Scene.Notification.NotificationDescription.MentionedYou" = "mentioned you";

View File

@ -121,6 +121,50 @@
<string>Followed by %1$@, and %ld mutuals</string>
</dict>
</dict>
<key>plural.count.others</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_others@</string>
<key>count_others</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>no others</string>
<key>one</key>
<string>one other</string>
<key>few</key>
<string>%ld others</string>
<key>many</key>
<string>%ld others</string>
<key>other</key>
<string>%ld others</string>
</dict>
</dict>
<key>plural.count.poll_that_you_and_others_voted_in</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_others@</string>
<key>count_others</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>a poll that you voted in</string>
<key>one</key>
<string>a poll that you and one other voted in</string>
<key>few</key>
<string>a poll that you and %ld others voted in</string>
<key>many</key>
<string>a poll that you and %ld others voted in</string>
<key>other</key>
<string>a poll that you and %ld others voted in</string>
</dict>
</dict>
<key>plural.count.metric_formatted.post</key>
<dict>
<key>NSStringLocalizedFormatKey</key>