Change translation strings of grouped notification label to have full context (#31486)

shrike
mogaminsk 2024-08-21 17:56:36 +09:00 committed by GitHub
parent b91264b1f3
commit 8c7642cd18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 155 additions and 108 deletions

View File

@ -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>
);
};

View File

@ -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 }}
/>
);
};

View File

@ -6,13 +6,27 @@ import type { NotificationGroupAdminSignUp } from 'mastodon/models/notification_
import type { LabelRenderer } from './notification_group_with_status'; import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status'; import { NotificationGroupWithStatus } from './notification_group_with_status';
const labelRenderer: LabelRenderer = (values) => ( const labelRenderer: LabelRenderer = (displayedName, total) => {
if (total === 1)
return (
<FormattedMessage <FormattedMessage
id='notification.admin.sign_up' id='notification.admin.sign_up'
defaultMessage='{name} signed up' defaultMessage='{name} signed up'
values={values} 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<{ export const NotificationAdminSignUp: React.FC<{
notification: NotificationGroupAdminSignUp; notification: NotificationGroupAdminSignUp;

View File

@ -1,5 +1,7 @@
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
import type { NotificationGroupFavourite } from 'mastodon/models/notification_group'; import type { NotificationGroupFavourite } from 'mastodon/models/notification_group';
import { useAppSelector } from 'mastodon/store'; import { useAppSelector } from 'mastodon/store';
@ -7,13 +9,29 @@ import { useAppSelector } from 'mastodon/store';
import type { LabelRenderer } from './notification_group_with_status'; import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status'; import { NotificationGroupWithStatus } from './notification_group_with_status';
const labelRenderer: LabelRenderer = (values) => ( const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
if (total === 1)
return (
<FormattedMessage <FormattedMessage
id='notification.favourite' id='notification.favourite'
defaultMessage='{name} favorited your status' defaultMessage='{name} favorited your status'
values={values} 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<{ export const NotificationFavourite: React.FC<{
notification: NotificationGroupFavourite; notification: NotificationGroupFavourite;

View File

@ -10,13 +10,27 @@ import { useAppSelector } from 'mastodon/store';
import type { LabelRenderer } from './notification_group_with_status'; import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status'; import { NotificationGroupWithStatus } from './notification_group_with_status';
const labelRenderer: LabelRenderer = (values) => ( const labelRenderer: LabelRenderer = (displayedName, total) => {
if (total === 1)
return (
<FormattedMessage <FormattedMessage
id='notification.follow' id='notification.follow'
defaultMessage='{name} followed you' defaultMessage='{name} followed you'
values={values} 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 FollowerCount: React.FC<{ accountId: string }> = ({ accountId }) => {
const account = useAppSelector((s) => s.accounts.get(accountId)); const account = useAppSelector((s) => s.accounts.get(accountId));

View File

@ -21,13 +21,27 @@ const messages = defineMessages({
reject: { id: 'follow_request.reject', defaultMessage: 'Reject' }, reject: { id: 'follow_request.reject', defaultMessage: 'Reject' },
}); });
const labelRenderer: LabelRenderer = (values) => ( const labelRenderer: LabelRenderer = (displayedName, total) => {
if (total === 1)
return (
<FormattedMessage <FormattedMessage
id='notification.follow_request' id='notification.follow_request'
defaultMessage='{name} has requested to follow you' defaultMessage='{name} has requested to follow you'
values={values} 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<{ export const NotificationFollowRequest: React.FC<{
notification: NotificationGroupFollowRequest; notification: NotificationGroupFollowRequest;

View File

@ -12,11 +12,13 @@ import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import { useAppDispatch } from 'mastodon/store'; import { useAppDispatch } from 'mastodon/store';
import { AvatarGroup } from './avatar_group'; import { AvatarGroup } from './avatar_group';
import { DisplayedName } from './displayed_name';
import { EmbeddedStatus } from './embedded_status'; import { EmbeddedStatus } from './embedded_status';
import { NamesList } from './names_list';
export type LabelRenderer = ( export type LabelRenderer = (
values: Record<string, React.ReactNode>, displayedName: JSX.Element,
total: number,
seeMoreHref?: string,
) => JSX.Element; ) => JSX.Element;
export const NotificationGroupWithStatus: React.FC<{ export const NotificationGroupWithStatus: React.FC<{
@ -50,15 +52,11 @@ export const NotificationGroupWithStatus: React.FC<{
const label = useMemo( const label = useMemo(
() => () =>
labelRenderer({ labelRenderer(
name: ( <DisplayedName accountIds={accountIds} />,
<NamesList count,
accountIds={accountIds} labelSeeMoreHref,
total={count}
seeMoreHref={labelSeeMoreHref}
/>
), ),
}),
[labelRenderer, accountIds, count, labelSeeMoreHref], [labelRenderer, accountIds, count, labelSeeMoreHref],
); );

View File

@ -1,5 +1,7 @@
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
import type { NotificationGroupReblog } from 'mastodon/models/notification_group'; import type { NotificationGroupReblog } from 'mastodon/models/notification_group';
import { useAppSelector } from 'mastodon/store'; import { useAppSelector } from 'mastodon/store';
@ -7,13 +9,29 @@ import { useAppSelector } from 'mastodon/store';
import type { LabelRenderer } from './notification_group_with_status'; import type { LabelRenderer } from './notification_group_with_status';
import { NotificationGroupWithStatus } from './notification_group_with_status'; import { NotificationGroupWithStatus } from './notification_group_with_status';
const labelRenderer: LabelRenderer = (values) => ( const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
if (total === 1)
return (
<FormattedMessage <FormattedMessage
id='notification.reblog' id='notification.reblog'
defaultMessage='{name} boosted your status' defaultMessage='{name} boosted your status'
values={values} 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<{ export const NotificationReblog: React.FC<{
notification: NotificationGroupReblog; notification: NotificationGroupReblog;

View File

@ -6,11 +6,11 @@ import type { NotificationGroupStatus } from 'mastodon/models/notification_group
import type { LabelRenderer } from './notification_group_with_status'; import type { LabelRenderer } from './notification_group_with_status';
import { NotificationWithStatus } from './notification_with_status'; import { NotificationWithStatus } from './notification_with_status';
const labelRenderer: LabelRenderer = (values) => ( const labelRenderer: LabelRenderer = (displayedName) => (
<FormattedMessage <FormattedMessage
id='notification.status' id='notification.status'
defaultMessage='{name} just posted' defaultMessage='{name} just posted'
values={values} values={{ name: displayedName }}
/> />
); );

View File

@ -6,11 +6,11 @@ import type { NotificationGroupUpdate } from 'mastodon/models/notification_group
import type { LabelRenderer } from './notification_group_with_status'; import type { LabelRenderer } from './notification_group_with_status';
import { NotificationWithStatus } from './notification_with_status'; import { NotificationWithStatus } from './notification_with_status';
const labelRenderer: LabelRenderer = (values) => ( const labelRenderer: LabelRenderer = (displayedName) => (
<FormattedMessage <FormattedMessage
id='notification.update' id='notification.update'
defaultMessage='{name} edited a post' defaultMessage='{name} edited a post'
values={values} values={{ name: displayedName }}
/> />
); );

View File

@ -15,7 +15,7 @@ import { Icon } from 'mastodon/components/icon';
import Status from 'mastodon/containers/status_container'; import Status from 'mastodon/containers/status_container';
import { useAppSelector, useAppDispatch } from 'mastodon/store'; import { useAppSelector, useAppDispatch } from 'mastodon/store';
import { NamesList } from './names_list'; import { DisplayedName } from './displayed_name';
import type { LabelRenderer } from './notification_group_with_status'; import type { LabelRenderer } from './notification_group_with_status';
export const NotificationWithStatus: React.FC<{ export const NotificationWithStatus: React.FC<{
@ -40,10 +40,7 @@ export const NotificationWithStatus: React.FC<{
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const label = useMemo( const label = useMemo(
() => () => labelRenderer(<DisplayedName accountIds={accountIds} />, count),
labelRenderer({
name: <NamesList accountIds={accountIds} total={count} />,
}),
[labelRenderer, accountIds, count], [labelRenderer, accountIds, count],
); );

View File

@ -463,8 +463,6 @@
"mute_modal.title": "Mute user?", "mute_modal.title": "Mute user?",
"mute_modal.you_wont_see_mentions": "You won't see posts that mention them.", "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.", "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.about": "About",
"navigation_bar.advanced_interface": "Open in advanced web interface", "navigation_bar.advanced_interface": "Open in advanced web interface",
"navigation_bar.blocks": "Blocked users", "navigation_bar.blocks": "Blocked users",
@ -497,9 +495,13 @@
"notification.admin.report_statuses": "{name} reported {target} for {category}", "notification.admin.report_statuses": "{name} reported {target} for {category}",
"notification.admin.report_statuses_other": "{name} reported {target}", "notification.admin.report_statuses_other": "{name} reported {target}",
"notification.admin.sign_up": "{name} signed up", "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} 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} 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} 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.mention": "Mention",
"notification.label.private_mention": "Private mention", "notification.label.private_mention": "Private mention",
"notification.label.private_reply": "Private reply", "notification.label.private_reply": "Private reply",
@ -517,6 +519,7 @@
"notification.own_poll": "Your poll has ended", "notification.own_poll": "Your poll has ended",
"notification.poll": "A poll you voted in has ended", "notification.poll": "A poll you voted in has ended",
"notification.reblog": "{name} boosted your post", "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": "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.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.", "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.",