From 8c7642cd186315f364a3a2d9090ebd87c2d684c6 Mon Sep 17 00:00:00 2001
From: mogaminsk <mgmnjp@icloud.com>
Date: Wed, 21 Aug 2024 17:56:36 +0900
Subject: [PATCH] Change translation strings of grouped notification label to
 have full context (#31486)

---
 .../components/displayed_name.tsx             | 22 ++++++++
 .../components/names_list.tsx                 | 51 -------------------
 .../components/notification_admin_sign_up.tsx | 28 +++++++---
 .../components/notification_favourite.tsx     | 32 +++++++++---
 .../components/notification_follow.tsx        | 28 +++++++---
 .../notification_follow_request.tsx           | 28 +++++++---
 .../notification_group_with_status.tsx        | 20 ++++----
 .../components/notification_reblog.tsx        | 32 +++++++++---
 .../components/notification_status.tsx        |  4 +-
 .../components/notification_update.tsx        |  4 +-
 .../components/notification_with_status.tsx   |  7 +--
 app/javascript/mastodon/locales/en.json       |  7 ++-
 12 files changed, 155 insertions(+), 108 deletions(-)
 create mode 100644 app/javascript/mastodon/features/notifications_v2/components/displayed_name.tsx
 delete mode 100644 app/javascript/mastodon/features/notifications_v2/components/names_list.tsx

diff --git a/app/javascript/mastodon/features/notifications_v2/components/displayed_name.tsx b/app/javascript/mastodon/features/notifications_v2/components/displayed_name.tsx
new file mode 100644
index 000000000..82ecb93ee
--- /dev/null
+++ b/app/javascript/mastodon/features/notifications_v2/components/displayed_name.tsx
@@ -0,0 +1,22 @@
+import { Link } from 'react-router-dom';
+
+import { useAppSelector } from 'mastodon/store';
+
+export const DisplayedName: React.FC<{
+  accountIds: string[];
+}> = ({ accountIds }) => {
+  const lastAccountId = accountIds[0] ?? '0';
+  const account = useAppSelector((state) => state.accounts.get(lastAccountId));
+
+  if (!account) return null;
+
+  return (
+    <Link
+      to={`/@${account.acct}`}
+      title={`@${account.acct}`}
+      data-hover-card-account={account.id}
+    >
+      <bdi dangerouslySetInnerHTML={{ __html: account.display_name_html }} />
+    </Link>
+  );
+};
diff --git a/app/javascript/mastodon/features/notifications_v2/components/names_list.tsx b/app/javascript/mastodon/features/notifications_v2/components/names_list.tsx
deleted file mode 100644
index 3d70cc0b6..000000000
--- a/app/javascript/mastodon/features/notifications_v2/components/names_list.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { FormattedMessage } from 'react-intl';
-
-import { Link } from 'react-router-dom';
-
-import { useAppSelector } from 'mastodon/store';
-
-export const NamesList: React.FC<{
-  accountIds: string[];
-  total: number;
-  seeMoreHref?: string;
-}> = ({ accountIds, total, seeMoreHref }) => {
-  const lastAccountId = accountIds[0] ?? '0';
-  const account = useAppSelector((state) => state.accounts.get(lastAccountId));
-
-  if (!account) return null;
-
-  const displayedName = (
-    <Link
-      to={`/@${account.acct}`}
-      title={`@${account.acct}`}
-      data-hover-card-account={account.id}
-    >
-      <bdi dangerouslySetInnerHTML={{ __html: account.display_name_html }} />
-    </Link>
-  );
-
-  if (total === 1) {
-    return displayedName;
-  }
-
-  if (seeMoreHref)
-    return (
-      <FormattedMessage
-        id='name_and_others_with_link'
-        defaultMessage='{name} and <a>{count, plural, one {# other} other {# others}}</a>'
-        values={{
-          name: displayedName,
-          count: total - 1,
-          a: (chunks) => <Link to={seeMoreHref}>{chunks}</Link>,
-        }}
-      />
-    );
-
-  return (
-    <FormattedMessage
-      id='name_and_others'
-      defaultMessage='{name} and {count, plural, one {# other} other {# others}}'
-      values={{ name: displayedName, count: total - 1 }}
-    />
-  );
-};
diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_admin_sign_up.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_admin_sign_up.tsx
index 9f7afc63f..73a5851ad 100644
--- a/app/javascript/mastodon/features/notifications_v2/components/notification_admin_sign_up.tsx
+++ b/app/javascript/mastodon/features/notifications_v2/components/notification_admin_sign_up.tsx
@@ -6,13 +6,27 @@ import type { NotificationGroupAdminSignUp } from 'mastodon/models/notification_
 import type { LabelRenderer } from './notification_group_with_status';
 import { NotificationGroupWithStatus } from './notification_group_with_status';
 
-const labelRenderer: LabelRenderer = (values) => (
-  <FormattedMessage
-    id='notification.admin.sign_up'
-    defaultMessage='{name} signed up'
-    values={values}
-  />
-);
+const labelRenderer: LabelRenderer = (displayedName, total) => {
+  if (total === 1)
+    return (
+      <FormattedMessage
+        id='notification.admin.sign_up'
+        defaultMessage='{name} signed up'
+        values={{ name: displayedName }}
+      />
+    );
+
+  return (
+    <FormattedMessage
+      id='notification.admin.sign_up.name_and_others'
+      defaultMessage='{name} and {count, plural, one {# other} other {# others}} signed up'
+      values={{
+        name: displayedName,
+        count: total - 1,
+      }}
+    />
+  );
+};
 
 export const NotificationAdminSignUp: React.FC<{
   notification: NotificationGroupAdminSignUp;
diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_favourite.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_favourite.tsx
index 22838fe69..eba37fe93 100644
--- a/app/javascript/mastodon/features/notifications_v2/components/notification_favourite.tsx
+++ b/app/javascript/mastodon/features/notifications_v2/components/notification_favourite.tsx
@@ -1,5 +1,7 @@
 import { FormattedMessage } from 'react-intl';
 
+import { Link } from 'react-router-dom';
+
 import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
 import type { NotificationGroupFavourite } from 'mastodon/models/notification_group';
 import { useAppSelector } from 'mastodon/store';
@@ -7,13 +9,29 @@ import { useAppSelector } from 'mastodon/store';
 import type { LabelRenderer } from './notification_group_with_status';
 import { NotificationGroupWithStatus } from './notification_group_with_status';
 
-const labelRenderer: LabelRenderer = (values) => (
-  <FormattedMessage
-    id='notification.favourite'
-    defaultMessage='{name} favorited your status'
-    values={values}
-  />
-);
+const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
+  if (total === 1)
+    return (
+      <FormattedMessage
+        id='notification.favourite'
+        defaultMessage='{name} favorited your status'
+        values={{ name: displayedName }}
+      />
+    );
+
+  return (
+    <FormattedMessage
+      id='notification.favourite.name_and_others_with_link'
+      defaultMessage='{name} and <a>{count, plural, one {# other} other {# others}}</a> favorited your post'
+      values={{
+        name: displayedName,
+        count: total - 1,
+        a: (chunks) =>
+          seeMoreHref ? <Link to={seeMoreHref}>{chunks}</Link> : chunks,
+      }}
+    />
+  );
+};
 
 export const NotificationFavourite: React.FC<{
   notification: NotificationGroupFavourite;
diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_follow.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_follow.tsx
index 3760096d4..6a9a45d24 100644
--- a/app/javascript/mastodon/features/notifications_v2/components/notification_follow.tsx
+++ b/app/javascript/mastodon/features/notifications_v2/components/notification_follow.tsx
@@ -10,13 +10,27 @@ import { useAppSelector } from 'mastodon/store';
 import type { LabelRenderer } from './notification_group_with_status';
 import { NotificationGroupWithStatus } from './notification_group_with_status';
 
-const labelRenderer: LabelRenderer = (values) => (
-  <FormattedMessage
-    id='notification.follow'
-    defaultMessage='{name} followed you'
-    values={values}
-  />
-);
+const labelRenderer: LabelRenderer = (displayedName, total) => {
+  if (total === 1)
+    return (
+      <FormattedMessage
+        id='notification.follow'
+        defaultMessage='{name} followed you'
+        values={{ name: displayedName }}
+      />
+    );
+
+  return (
+    <FormattedMessage
+      id='notification.follow.name_and_others'
+      defaultMessage='{name} and {count, plural, one {# other} other {# others}} followed you'
+      values={{
+        name: displayedName,
+        count: total - 1,
+      }}
+    />
+  );
+};
 
 const FollowerCount: React.FC<{ accountId: string }> = ({ accountId }) => {
   const account = useAppSelector((s) => s.accounts.get(accountId));
diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_follow_request.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_follow_request.tsx
index 281bfd94a..5f61f2cd7 100644
--- a/app/javascript/mastodon/features/notifications_v2/components/notification_follow_request.tsx
+++ b/app/javascript/mastodon/features/notifications_v2/components/notification_follow_request.tsx
@@ -21,13 +21,27 @@ const messages = defineMessages({
   reject: { id: 'follow_request.reject', defaultMessage: 'Reject' },
 });
 
-const labelRenderer: LabelRenderer = (values) => (
-  <FormattedMessage
-    id='notification.follow_request'
-    defaultMessage='{name} has requested to follow you'
-    values={values}
-  />
-);
+const labelRenderer: LabelRenderer = (displayedName, total) => {
+  if (total === 1)
+    return (
+      <FormattedMessage
+        id='notification.follow_request'
+        defaultMessage='{name} has requested to follow you'
+        values={{ name: displayedName }}
+      />
+    );
+
+  return (
+    <FormattedMessage
+      id='notification.follow_request.name_and_others'
+      defaultMessage='{name} and {count, plural, one {# other} other {# others}} has requested to follow you'
+      values={{
+        name: displayedName,
+        count: total - 1,
+      }}
+    />
+  );
+};
 
 export const NotificationFollowRequest: React.FC<{
   notification: NotificationGroupFollowRequest;
diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx
index 8f555956e..343a9bc4c 100644
--- a/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx
+++ b/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx
@@ -12,11 +12,13 @@ import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
 import { useAppDispatch } from 'mastodon/store';
 
 import { AvatarGroup } from './avatar_group';
+import { DisplayedName } from './displayed_name';
 import { EmbeddedStatus } from './embedded_status';
-import { NamesList } from './names_list';
 
 export type LabelRenderer = (
-  values: Record<string, React.ReactNode>,
+  displayedName: JSX.Element,
+  total: number,
+  seeMoreHref?: string,
 ) => JSX.Element;
 
 export const NotificationGroupWithStatus: React.FC<{
@@ -50,15 +52,11 @@ export const NotificationGroupWithStatus: React.FC<{
 
   const label = useMemo(
     () =>
-      labelRenderer({
-        name: (
-          <NamesList
-            accountIds={accountIds}
-            total={count}
-            seeMoreHref={labelSeeMoreHref}
-          />
-        ),
-      }),
+      labelRenderer(
+        <DisplayedName accountIds={accountIds} />,
+        count,
+        labelSeeMoreHref,
+      ),
     [labelRenderer, accountIds, count, labelSeeMoreHref],
   );
 
diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_reblog.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_reblog.tsx
index 062556868..7b3bda85e 100644
--- a/app/javascript/mastodon/features/notifications_v2/components/notification_reblog.tsx
+++ b/app/javascript/mastodon/features/notifications_v2/components/notification_reblog.tsx
@@ -1,5 +1,7 @@
 import { FormattedMessage } from 'react-intl';
 
+import { Link } from 'react-router-dom';
+
 import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
 import type { NotificationGroupReblog } from 'mastodon/models/notification_group';
 import { useAppSelector } from 'mastodon/store';
@@ -7,13 +9,29 @@ import { useAppSelector } from 'mastodon/store';
 import type { LabelRenderer } from './notification_group_with_status';
 import { NotificationGroupWithStatus } from './notification_group_with_status';
 
-const labelRenderer: LabelRenderer = (values) => (
-  <FormattedMessage
-    id='notification.reblog'
-    defaultMessage='{name} boosted your status'
-    values={values}
-  />
-);
+const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
+  if (total === 1)
+    return (
+      <FormattedMessage
+        id='notification.reblog'
+        defaultMessage='{name} boosted your status'
+        values={{ name: displayedName }}
+      />
+    );
+
+  return (
+    <FormattedMessage
+      id='notification.reblog.name_and_others_with_link'
+      defaultMessage='{name} and <a>{count, plural, one {# other} other {# others}}</a> boosted your post'
+      values={{
+        name: displayedName,
+        count: total - 1,
+        a: (chunks) =>
+          seeMoreHref ? <Link to={seeMoreHref}>{chunks}</Link> : chunks,
+      }}
+    />
+  );
+};
 
 export const NotificationReblog: React.FC<{
   notification: NotificationGroupReblog;
diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_status.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_status.tsx
index 9ade355a7..2955c3aea 100644
--- a/app/javascript/mastodon/features/notifications_v2/components/notification_status.tsx
+++ b/app/javascript/mastodon/features/notifications_v2/components/notification_status.tsx
@@ -6,11 +6,11 @@ import type { NotificationGroupStatus } from 'mastodon/models/notification_group
 import type { LabelRenderer } from './notification_group_with_status';
 import { NotificationWithStatus } from './notification_with_status';
 
-const labelRenderer: LabelRenderer = (values) => (
+const labelRenderer: LabelRenderer = (displayedName) => (
   <FormattedMessage
     id='notification.status'
     defaultMessage='{name} just posted'
-    values={values}
+    values={{ name: displayedName }}
   />
 );
 
diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_update.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_update.tsx
index c518367bf..731f319f8 100644
--- a/app/javascript/mastodon/features/notifications_v2/components/notification_update.tsx
+++ b/app/javascript/mastodon/features/notifications_v2/components/notification_update.tsx
@@ -6,11 +6,11 @@ import type { NotificationGroupUpdate } from 'mastodon/models/notification_group
 import type { LabelRenderer } from './notification_group_with_status';
 import { NotificationWithStatus } from './notification_with_status';
 
-const labelRenderer: LabelRenderer = (values) => (
+const labelRenderer: LabelRenderer = (displayedName) => (
   <FormattedMessage
     id='notification.update'
     defaultMessage='{name} edited a post'
-    values={values}
+    values={{ name: displayedName }}
   />
 );
 
diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_with_status.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_with_status.tsx
index 5d5cb9818..a1c275a1f 100644
--- a/app/javascript/mastodon/features/notifications_v2/components/notification_with_status.tsx
+++ b/app/javascript/mastodon/features/notifications_v2/components/notification_with_status.tsx
@@ -15,7 +15,7 @@ import { Icon } from 'mastodon/components/icon';
 import Status from 'mastodon/containers/status_container';
 import { useAppSelector, useAppDispatch } from 'mastodon/store';
 
-import { NamesList } from './names_list';
+import { DisplayedName } from './displayed_name';
 import type { LabelRenderer } from './notification_group_with_status';
 
 export const NotificationWithStatus: React.FC<{
@@ -40,10 +40,7 @@ export const NotificationWithStatus: React.FC<{
   const dispatch = useAppDispatch();
 
   const label = useMemo(
-    () =>
-      labelRenderer({
-        name: <NamesList accountIds={accountIds} total={count} />,
-      }),
+    () => labelRenderer(<DisplayedName accountIds={accountIds} />, count),
     [labelRenderer, accountIds, count],
   );
 
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 43ff01579..ba351032f 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -463,8 +463,6 @@
   "mute_modal.title": "Mute user?",
   "mute_modal.you_wont_see_mentions": "You won't see posts that mention them.",
   "mute_modal.you_wont_see_posts": "They can still see your posts, but you won't see theirs.",
-  "name_and_others": "{name} and {count, plural, one {# other} other {# others}}",
-  "name_and_others_with_link": "{name} and <a>{count, plural, one {# other} other {# others}}</a>",
   "navigation_bar.about": "About",
   "navigation_bar.advanced_interface": "Open in advanced web interface",
   "navigation_bar.blocks": "Blocked users",
@@ -497,9 +495,13 @@
   "notification.admin.report_statuses": "{name} reported {target} for {category}",
   "notification.admin.report_statuses_other": "{name} reported {target}",
   "notification.admin.sign_up": "{name} signed up",
+  "notification.admin.sign_up.name_and_others": "{name} and {count, plural, one {# other} other {# others}} signed up",
   "notification.favourite": "{name} favorited your post",
+  "notification.favourite.name_and_others_with_link": "{name} and <a>{count, plural, one {# other} other {# others}}</a> favorited your post",
   "notification.follow": "{name} followed you",
+  "notification.follow.name_and_others": "{name} and {count, plural, one {# other} other {# others}} followed you",
   "notification.follow_request": "{name} has requested to follow you",
+  "notification.follow_request.name_and_others": "{name} and {count, plural, one {# other} other {# others}} has requested to follow you",
   "notification.label.mention": "Mention",
   "notification.label.private_mention": "Private mention",
   "notification.label.private_reply": "Private reply",
@@ -517,6 +519,7 @@
   "notification.own_poll": "Your poll has ended",
   "notification.poll": "A poll you voted in has ended",
   "notification.reblog": "{name} boosted your post",
+  "notification.reblog.name_and_others_with_link": "{name} and <a>{count, plural, one {# other} other {# others}}</a> boosted your post",
   "notification.relationships_severance_event": "Lost connections with {name}",
   "notification.relationships_severance_event.account_suspension": "An admin from {from} has suspended {target}, which means you can no longer receive updates from them or interact with them.",
   "notification.relationships_severance_event.domain_block": "An admin from {from} has blocked {target}, including {followersCount} of your followers and {followingCount, plural, one {# account} other {# accounts}} you follow.",