Use ICU number/plural formatting
This commit is contained in:
parent
aba8882d0a
commit
da24cc5e95
30 changed files with 254 additions and 222 deletions
|
@ -38,7 +38,7 @@ export function AddGroupMemberErrorDialog(props: PropsType): JSX.Element {
|
|||
const { maximumNumberOfContacts } = props;
|
||||
title = i18n('icu:chooseGroupMembers__maximum-group-size__title');
|
||||
body = i18n('icu:chooseGroupMembers__maximum-group-size__body', {
|
||||
max: maximumNumberOfContacts.toString(),
|
||||
max: maximumNumberOfContacts,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ export function AddGroupMemberErrorDialog(props: PropsType): JSX.Element {
|
|||
body = i18n(
|
||||
'icu:chooseGroupMembers__maximum-recommended-group-size__body',
|
||||
{
|
||||
max: recommendedMaximumNumberOfContacts.toString(),
|
||||
max: recommendedMaximumNumberOfContacts,
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
|
|
@ -349,7 +349,7 @@ function CustomColorBubble({
|
|||
title={i18n('icu:ChatColorPicker__delete--title')}
|
||||
>
|
||||
{i18n('icu:ChatColorPicker__delete--message', {
|
||||
num: String(confirmDeleteCount),
|
||||
num: confirmDeleteCount,
|
||||
})}
|
||||
</ConfirmationDialog>
|
||||
) : null}
|
||||
|
|
|
@ -360,7 +360,7 @@ export function ConversationList({
|
|||
get(lastMessage, 'text') ||
|
||||
i18n('icu:ConversationList__last-message-undefined'),
|
||||
title,
|
||||
unreadCount: String(unreadCount),
|
||||
unreadCount,
|
||||
})}
|
||||
>
|
||||
<ConversationListItem
|
||||
|
|
|
@ -49,12 +49,6 @@ export const GroupV2JoinDialog = React.memo(function GroupV2JoinDialogInner(
|
|||
const joinString = approvalRequired
|
||||
? i18n('icu:GroupV2--join--request-to-join-button')
|
||||
: i18n('icu:GroupV2--join--join-button');
|
||||
const memberString =
|
||||
memberCount === 1
|
||||
? i18n('icu:GroupV2--join--member-count--single')
|
||||
: i18n('icu:GroupV2--join--member-count--multiple', {
|
||||
count: memberCount.toString(),
|
||||
});
|
||||
|
||||
const wrappedJoin = React.useCallback(() => {
|
||||
setIsWorking(true);
|
||||
|
@ -93,9 +87,7 @@ export const GroupV2JoinDialog = React.memo(function GroupV2JoinDialogInner(
|
|||
</div>
|
||||
<div className="module-group-v2-join-dialog__title">{title}</div>
|
||||
<div className="module-group-v2-join-dialog__metadata">
|
||||
{i18n('icu:GroupV2--join--group-metadata', {
|
||||
memberCount: memberString,
|
||||
})}
|
||||
{i18n('icu:GroupV2--join--group-metadata--full', { memberCount })}
|
||||
</div>
|
||||
{groupDescription && (
|
||||
<div className="module-group-v2-join-dialog__description">
|
||||
|
|
|
@ -150,7 +150,7 @@ function GroupCallMessage({
|
|||
ringer: ringerNode,
|
||||
first,
|
||||
second,
|
||||
remaining: String(otherMembersRung.length - 2),
|
||||
remaining: otherMembersRung.length - 2,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -27,12 +27,10 @@ export function NewlyCreatedGroupInvitedContactsDialog({
|
|||
onClose,
|
||||
theme,
|
||||
}: PropsType): JSX.Element {
|
||||
let title: string;
|
||||
let body: ReactNode;
|
||||
if (contacts.length === 1) {
|
||||
const contact = contacts[0];
|
||||
|
||||
title = i18n('icu:NewlyCreatedGroupInvitedContactsDialog--title--one');
|
||||
body = (
|
||||
<>
|
||||
<GroupDialog.Paragraph>
|
||||
|
@ -50,9 +48,6 @@ export function NewlyCreatedGroupInvitedContactsDialog({
|
|||
</>
|
||||
);
|
||||
} else {
|
||||
title = i18n('icu:NewlyCreatedGroupInvitedContactsDialog--title--many', {
|
||||
count: contacts.length.toString(),
|
||||
});
|
||||
body = (
|
||||
<>
|
||||
<GroupDialog.Paragraph>
|
||||
|
@ -89,7 +84,9 @@ export function NewlyCreatedGroupInvitedContactsDialog({
|
|||
);
|
||||
}}
|
||||
onClose={onClose}
|
||||
title={title}
|
||||
title={i18n('icu:NewlyCreatedGroupInvitedContactsDialog--title', {
|
||||
count: contacts.length,
|
||||
})}
|
||||
>
|
||||
{body}
|
||||
</GroupDialog>
|
||||
|
|
|
@ -883,15 +883,9 @@ export function Preferences({
|
|||
<SettingsRow>
|
||||
<Control
|
||||
left={i18n('icu:Preferences--blocked')}
|
||||
right={
|
||||
blockedCount === 1
|
||||
? i18n('icu:Preferences--blocked-count-singular', {
|
||||
num: String(blockedCount),
|
||||
})
|
||||
: i18n('icu:Preferences--blocked-count-plural', {
|
||||
num: String(blockedCount || 0),
|
||||
})
|
||||
}
|
||||
right={i18n('icu:Preferences--blocked-count', {
|
||||
num: blockedCount,
|
||||
})}
|
||||
/>
|
||||
</SettingsRow>
|
||||
<SettingsRow title={i18n('icu:Preferences--messaging')}>
|
||||
|
|
|
@ -643,15 +643,17 @@ export function ProfileEditor({
|
|||
<div className="ProfileEditor__info">
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:ProfileEditor--info"
|
||||
id="icu:ProfileEditor--info--link"
|
||||
components={{
|
||||
learnMore: (
|
||||
// This is a render prop, not a component
|
||||
// eslint-disable-next-line react/no-unstable-nested-components
|
||||
learnMoreLink: parts => (
|
||||
<a
|
||||
href="https://support.signal.org/hc/en-us/articles/360007459591"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{i18n('icu:ProfileEditor--learnMore')}
|
||||
{parts}
|
||||
</a>
|
||||
),
|
||||
}}
|
||||
|
|
|
@ -37,7 +37,7 @@ export function SharedGroupNames({
|
|||
group1: firstThreeGroups[0],
|
||||
group2: firstThreeGroups[1],
|
||||
group3: firstThreeGroups[2],
|
||||
remainingCount: remainingCount.toString(),
|
||||
remainingCount,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -816,28 +816,28 @@ export function EditMyStoryPrivacy({
|
|||
toggleSignalConnectionsModal,
|
||||
signalConnectionsCount,
|
||||
}: EditMyStoryPrivacyPropsType): JSX.Element {
|
||||
const learnMore = (
|
||||
const learnMoreLink = (parts: Array<JSX.Element | string>) => (
|
||||
<button
|
||||
className="StoriesSettingsModal__disclaimer__learn-more"
|
||||
onClick={toggleSignalConnectionsModal}
|
||||
type="button"
|
||||
>
|
||||
{i18n('icu:StoriesSettings__mine__disclaimer--learn-more')}
|
||||
{parts}
|
||||
</button>
|
||||
);
|
||||
const disclaimerElement = (
|
||||
<div className="StoriesSettingsModal__disclaimer">
|
||||
{kind === 'mine' ? (
|
||||
<Intl
|
||||
components={{ learnMore }}
|
||||
components={{ learnMoreLink }}
|
||||
i18n={i18n}
|
||||
id="icu:StoriesSettings__mine__disclaimer"
|
||||
id="icu:StoriesSettings__mine__disclaimer--link"
|
||||
/>
|
||||
) : (
|
||||
<Intl
|
||||
components={{ learnMore }}
|
||||
components={{ learnMoreLink }}
|
||||
i18n={i18n}
|
||||
id="icu:SendStoryModal__privacy-disclaimer"
|
||||
id="icu:SendStoryModal__privacy-disclaimer--link"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -54,6 +54,10 @@ import { useRetryStorySend } from '../hooks/useRetryStorySend';
|
|||
import { resolveStorySendStatus } from '../util/resolveStorySendStatus';
|
||||
import { strictAssert } from '../util/assert';
|
||||
|
||||
function renderStrong(parts: Array<JSX.Element | string>) {
|
||||
return <strong>{parts}</strong>;
|
||||
}
|
||||
|
||||
export type PropsType = {
|
||||
currentIndex: number;
|
||||
deleteGroupStoryReply: (id: string) => void;
|
||||
|
@ -851,36 +855,21 @@ export function StoryViewer({
|
|||
{isSent && !hasViewReceiptSetting && !replyCount && (
|
||||
<>{i18n('icu:StoryViewer__views-off')}</>
|
||||
)}
|
||||
{isSent &&
|
||||
hasViewReceiptSetting &&
|
||||
(viewCount === 1 ? (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:MyStories__views--singular"
|
||||
components={{ num: <strong>{viewCount}</strong> }}
|
||||
/>
|
||||
) : (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:MyStories__views--plural"
|
||||
components={{ num: <strong>{viewCount}</strong> }}
|
||||
/>
|
||||
))}
|
||||
{isSent && hasViewReceiptSetting && (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:MyStories__views--strong"
|
||||
components={{ viewCount, strong: renderStrong }}
|
||||
/>
|
||||
)}
|
||||
{(isSent || viewCount > 0) && replyCount > 0 && ' '}
|
||||
{replyCount > 0 &&
|
||||
(replyCount === 1 ? (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:MyStories__replies--singular"
|
||||
components={{ num: <strong>{replyCount}</strong> }}
|
||||
/>
|
||||
) : (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:MyStories__replies--plural"
|
||||
components={{ num: <strong>{replyCount}</strong> }}
|
||||
/>
|
||||
))}
|
||||
{replyCount > 0 && (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:MyStories__replies"
|
||||
components={{ replyCount, strong: renderStrong }}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
) : null}
|
||||
{!isSent && !replyCount && (
|
||||
|
|
|
@ -20,7 +20,7 @@ export default {
|
|||
};
|
||||
|
||||
export const _ToastFileSize = (): JSX.Element => (
|
||||
<ToastFileSize {...defaultProps} limit="100" units="MB" />
|
||||
<ToastFileSize {...defaultProps} limit={100} units="MB" />
|
||||
);
|
||||
|
||||
_ToastFileSize.story = {
|
||||
|
|
|
@ -6,7 +6,7 @@ import type { LocalizerType } from '../types/Util';
|
|||
import { Toast } from './Toast';
|
||||
|
||||
export type ToastPropsType = {
|
||||
limit: string;
|
||||
limit: number;
|
||||
units: string;
|
||||
};
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ function renderCallingNotificationButton(
|
|||
disabledTooltipText = i18n(
|
||||
'icu:calling__call-notification__button__call-full-tooltip',
|
||||
{
|
||||
max: String(deviceCount),
|
||||
max: deviceCount,
|
||||
}
|
||||
);
|
||||
onClick = noop;
|
||||
|
|
|
@ -253,7 +253,7 @@ export function ContactSpoofingReviewDialog(props: PropsType): JSX.Element {
|
|||
<>
|
||||
<p>
|
||||
{i18n('icu:ContactSpoofingReviewDialog__group__description', {
|
||||
count: conversationInfos.length.toString(),
|
||||
count: conversationInfos.length,
|
||||
})}
|
||||
</p>
|
||||
<h2>
|
||||
|
|
|
@ -21,18 +21,22 @@ export function GroupV1DisabledActions({
|
|||
<p className="module-group-v1-disabled-actions__message">
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:GroupV1--Migration--disabled"
|
||||
id="icu:GroupV1--Migration--disabled--link"
|
||||
components={{
|
||||
learnMore: (
|
||||
<a
|
||||
href="https://support.signal.org/hc/articles/360007319331"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="module-group-v1-disabled-actions__message__learn-more"
|
||||
>
|
||||
{i18n('icu:MessageRequests--learn-more')}
|
||||
</a>
|
||||
),
|
||||
// This is a render prop, not a component
|
||||
// eslint-disable-next-line react/no-unstable-nested-components
|
||||
learnMoreLink: (...parts) => {
|
||||
return (
|
||||
<a
|
||||
href="https://support.signal.org/hc/articles/360007319331"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="module-group-v1-disabled-actions__message__learn-more"
|
||||
>
|
||||
{parts}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
|
|
|
@ -15,9 +15,7 @@ export const LastSeenIndicator = forwardRef<HTMLDivElement, Props>(
|
|||
const message =
|
||||
count === 1
|
||||
? i18n('icu:unreadMessage')
|
||||
: i18n('icu:unreadMessages', {
|
||||
count: String(count),
|
||||
});
|
||||
: i18n('icu:unreadMessages', { count });
|
||||
|
||||
return (
|
||||
<div className="module-last-seen-indicator" ref={ref}>
|
||||
|
|
|
@ -27,6 +27,17 @@ export type Props = {
|
|||
| 'deleteConversation'
|
||||
>;
|
||||
|
||||
const learnMoreLink = (parts: Array<JSX.Element | string>) => (
|
||||
<a
|
||||
href="https://support.signal.org/hc/articles/360007459591"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="module-message-request-actions__message__learn-more"
|
||||
>
|
||||
{parts}
|
||||
</a>
|
||||
);
|
||||
|
||||
export function MandatoryProfileSharingActions({
|
||||
acceptConversation,
|
||||
blockAndReportSpam,
|
||||
|
@ -49,17 +60,6 @@ export function MandatoryProfileSharingActions({
|
|||
</strong>
|
||||
);
|
||||
|
||||
const learnMore = (
|
||||
<a
|
||||
href="https://support.signal.org/hc/articles/360007459591"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="module-message-request-actions__message__learn-more"
|
||||
>
|
||||
{i18n('icu:MessageRequests--learn-more')}
|
||||
</a>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{mrState !== MessageRequestState.default ? (
|
||||
|
@ -85,14 +85,14 @@ export function MandatoryProfileSharingActions({
|
|||
{conversationType === 'direct' ? (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:MessageRequests--profile-sharing--direct"
|
||||
components={{ firstName: firstNameContact, learnMore }}
|
||||
id="icu:MessageRequests--profile-sharing--direct--link"
|
||||
components={{ firstName: firstNameContact, learnMoreLink }}
|
||||
/>
|
||||
) : (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:MessageRequests--profile-sharing--group"
|
||||
components={{ firstName: firstNameContact, learnMore }}
|
||||
id="icu:MessageRequests--profile-sharing--group--link"
|
||||
components={{ firstName: firstNameContact, learnMoreLink }}
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
|
|
|
@ -905,9 +905,11 @@ export class Timeline extends React.Component<
|
|||
text = (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:ContactSpoofing__same-name"
|
||||
id="icu:ContactSpoofing__same-name--link"
|
||||
components={{
|
||||
link: (
|
||||
// This is a render props, not a component
|
||||
// eslint-disable-next-line react/no-unstable-nested-components
|
||||
reviewRequestLink: parts => (
|
||||
<TimelineWarning.Link
|
||||
onClick={() => {
|
||||
reviewMessageRequestNameCollision({
|
||||
|
@ -915,7 +917,7 @@ export class Timeline extends React.Component<
|
|||
});
|
||||
}}
|
||||
>
|
||||
{i18n('icu:ContactSpoofing__same-name__link')}
|
||||
{parts}
|
||||
</TimelineWarning.Link>
|
||||
),
|
||||
}}
|
||||
|
@ -932,21 +934,21 @@ export class Timeline extends React.Component<
|
|||
text = (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="icu:ContactSpoofing__same-name-in-group"
|
||||
id="icu:ContactSpoofing__same-name-in-group--link"
|
||||
components={{
|
||||
count: Object.values(groupNameCollisions)
|
||||
.reduce(
|
||||
(result, conversations) => result + conversations.length,
|
||||
0
|
||||
)
|
||||
.toString(),
|
||||
link: (
|
||||
count: Object.values(groupNameCollisions).reduce(
|
||||
(result, conversations) => result + conversations.length,
|
||||
0
|
||||
),
|
||||
// This is a render props, not a component
|
||||
// eslint-disable-next-line react/no-unstable-nested-components
|
||||
reviewRequestLink: parts => (
|
||||
<TimelineWarning.Link
|
||||
onClick={() => {
|
||||
reviewGroupMemberNameCollision(id);
|
||||
}}
|
||||
>
|
||||
{i18n('icu:ContactSpoofing__same-name-in-group__link')}
|
||||
{parts}
|
||||
</TimelineWarning.Link>
|
||||
),
|
||||
}}
|
||||
|
|
|
@ -60,7 +60,7 @@ export function ConfirmAdditionsModal({
|
|||
i18n={i18n}
|
||||
id="icu:AddGroupMembersModal--confirm-title--many"
|
||||
components={{
|
||||
count: selectedContacts.length.toString(),
|
||||
count: selectedContacts.length,
|
||||
group: groupTitleNode,
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -67,7 +67,7 @@ export function ConversationDetailsHeader({
|
|||
subtitle = i18n('icu:ConversationDetailsHeader--add-group-description');
|
||||
} else {
|
||||
subtitle = i18n('icu:ConversationDetailsHeader--members', {
|
||||
number: memberships.length.toString(),
|
||||
number: memberships.length,
|
||||
});
|
||||
}
|
||||
} else if (!isMe) {
|
||||
|
|
|
@ -94,7 +94,7 @@ export function ConversationDetailsMembershipList({
|
|||
return (
|
||||
<PanelSection
|
||||
title={i18n('icu:ConversationDetailsMembershipList--title', {
|
||||
number: sortedMemberships.length.toString(),
|
||||
number: sortedMemberships.length,
|
||||
})}
|
||||
>
|
||||
{canAddNewMembers && (
|
||||
|
|
|
@ -108,7 +108,7 @@ export function PendingInvites({
|
|||
tabIndex={0}
|
||||
>
|
||||
{i18n('icu:PendingInvites--tab-requests', {
|
||||
count: String(pendingApprovalMemberships.length),
|
||||
count: pendingApprovalMemberships.length,
|
||||
})}
|
||||
</div>
|
||||
|
||||
|
@ -129,7 +129,7 @@ export function PendingInvites({
|
|||
tabIndex={0}
|
||||
>
|
||||
{i18n('icu:PendingInvites--tab-invites', {
|
||||
count: String(pendingMemberships.length),
|
||||
count: pendingMemberships.length,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -325,12 +325,8 @@ function getConfirmationMessage({
|
|||
|
||||
const name = inviter.title;
|
||||
|
||||
if (stagedMemberships.length === 1) {
|
||||
return i18n('icu:PendingInvites--revoke-from-singular', { name });
|
||||
}
|
||||
|
||||
return i18n('icu:PendingInvites--revoke-from-plural', {
|
||||
number: stagedMemberships.length.toString(),
|
||||
return i18n('icu:PendingInvites--revoke-from', {
|
||||
number: stagedMemberships.length,
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
@ -505,7 +501,7 @@ function MembersPendingProfileKey({
|
|||
}
|
||||
label={member.title}
|
||||
right={i18n('icu:PendingInvites--invited-count', {
|
||||
number: pendingMemberships.length.toString(),
|
||||
number: pendingMemberships.length,
|
||||
})}
|
||||
actions={
|
||||
conversation.areWeAdmin ? (
|
||||
|
|
|
@ -14,7 +14,7 @@ export type SmartContactRendererType<T> = (uuid: UUIDStringType) => T | string;
|
|||
export type StringRendererType<T> = (
|
||||
id: string,
|
||||
i18n: LocalizerType,
|
||||
components?: ReplacementValuesType<T | string>
|
||||
components?: ReplacementValuesType<T | string | number>
|
||||
) => T | string;
|
||||
|
||||
export type RenderOptionsType<T> = {
|
||||
|
@ -76,7 +76,10 @@ export function renderChangeDetail<T>(
|
|||
renderString,
|
||||
} = options;
|
||||
|
||||
function i18n(id: string, components?: ReplacementValuesType<T | string>) {
|
||||
function i18n(
|
||||
id: string,
|
||||
components?: ReplacementValuesType<T | number | string>
|
||||
) {
|
||||
return renderString(id, localizer, components);
|
||||
}
|
||||
|
||||
|
@ -530,17 +533,17 @@ export function renderChangeDetail<T>(
|
|||
|
||||
if (fromYou) {
|
||||
return i18n('icu:GroupV2--pending-add--many--you', {
|
||||
count: count.toString(),
|
||||
count,
|
||||
});
|
||||
}
|
||||
if (from) {
|
||||
return i18n('icu:GroupV2--pending-add--many--other', {
|
||||
memberName: renderContact(from),
|
||||
count: count.toString(),
|
||||
count,
|
||||
});
|
||||
}
|
||||
return i18n('icu:GroupV2--pending-add--many--unknown', {
|
||||
count: count.toString(),
|
||||
count,
|
||||
});
|
||||
}
|
||||
if (detail.type === 'pending-remove-one') {
|
||||
|
@ -647,7 +650,7 @@ export function renderChangeDetail<T>(
|
|||
return i18n(
|
||||
'icu:GroupV2--pending-remove--revoke-invite-from-you--many--you',
|
||||
|
||||
{ count: count.toString() }
|
||||
{ count }
|
||||
);
|
||||
}
|
||||
if (from) {
|
||||
|
@ -656,14 +659,14 @@ export function renderChangeDetail<T>(
|
|||
|
||||
{
|
||||
adminName: renderContact(from),
|
||||
count: count.toString(),
|
||||
count,
|
||||
}
|
||||
);
|
||||
}
|
||||
return i18n(
|
||||
'icu:GroupV2--pending-remove--revoke-invite-from-you--many--unknown',
|
||||
|
||||
{ count: count.toString() }
|
||||
{ count }
|
||||
);
|
||||
}
|
||||
if (inviter) {
|
||||
|
@ -672,7 +675,7 @@ export function renderChangeDetail<T>(
|
|||
'icu:GroupV2--pending-remove--revoke-invite-from--many--you',
|
||||
|
||||
{
|
||||
count: count.toString(),
|
||||
count,
|
||||
memberName: renderContact(inviter),
|
||||
}
|
||||
);
|
||||
|
@ -683,7 +686,7 @@ export function renderChangeDetail<T>(
|
|||
|
||||
{
|
||||
adminName: renderContact(from),
|
||||
count: count.toString(),
|
||||
count,
|
||||
memberName: renderContact(inviter),
|
||||
}
|
||||
);
|
||||
|
@ -692,14 +695,14 @@ export function renderChangeDetail<T>(
|
|||
'icu:GroupV2--pending-remove--revoke-invite-from--many--unknown',
|
||||
|
||||
{
|
||||
count: count.toString(),
|
||||
count,
|
||||
memberName: renderContact(inviter),
|
||||
}
|
||||
);
|
||||
}
|
||||
if (fromYou) {
|
||||
return i18n('icu:GroupV2--pending-remove--revoke--many--you', {
|
||||
count: count.toString(),
|
||||
count,
|
||||
});
|
||||
}
|
||||
if (from) {
|
||||
|
@ -708,14 +711,14 @@ export function renderChangeDetail<T>(
|
|||
|
||||
{
|
||||
memberName: renderContact(from),
|
||||
count: count.toString(),
|
||||
count,
|
||||
}
|
||||
);
|
||||
}
|
||||
return i18n(
|
||||
'icu:GroupV2--pending-remove--revoke--many--unknown',
|
||||
|
||||
{ count: count.toString() }
|
||||
{ count }
|
||||
);
|
||||
}
|
||||
if (detail.type === 'admin-approval-add-one') {
|
||||
|
@ -784,7 +787,7 @@ export function renderChangeDetail<T>(
|
|||
} else {
|
||||
firstMessage = i18n('icu:GroupV2--admin-approval-bounce', {
|
||||
joinerName: renderContact(uuid),
|
||||
numberOfRequests: String(times),
|
||||
numberOfRequests: times,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -510,7 +510,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
|||
renderString: (
|
||||
key: string,
|
||||
_i18n: unknown,
|
||||
components: ReplacementValuesType<string> | undefined
|
||||
components: ReplacementValuesType<string | number> | undefined
|
||||
) => {
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
return window.i18n(key, components);
|
||||
|
|
|
@ -518,12 +518,9 @@ async function getGroupPreview(
|
|||
const title =
|
||||
window.Signal.Groups.decryptGroupTitle(result.title, secretParams) ||
|
||||
window.i18n('icu:unknownGroup');
|
||||
const description =
|
||||
result.memberCount === 1 || result.memberCount === undefined
|
||||
? window.i18n('icu:GroupV2--join--member-count--single')
|
||||
: window.i18n('icu:GroupV2--join--member-count--multiple', {
|
||||
count: result.memberCount.toString(),
|
||||
});
|
||||
const description = window.i18n('icu:GroupV2--join--group-metadata--full', {
|
||||
count: result?.memberCount ?? 0,
|
||||
});
|
||||
let image: undefined | LinkPreviewImage;
|
||||
|
||||
if (result.avatar) {
|
||||
|
|
|
@ -38,13 +38,11 @@ describe('setupI18n', () => {
|
|||
);
|
||||
});
|
||||
it('returns a modern icu message formatted', () => {
|
||||
const actual = i18n('icu:ProfileEditor--info', {
|
||||
learnMore: 'LEARN MORE',
|
||||
});
|
||||
assert.equal(
|
||||
actual,
|
||||
'Your profile is encrypted. Your profile and changes to it will be visible to your contacts and when you start or accept new chats. LEARN MORE'
|
||||
const actual = i18n(
|
||||
'icu:AddUserToAnotherGroupModal__toast--adding-user-to-group',
|
||||
{ contact: 'CONTACT' }
|
||||
);
|
||||
assert.equal(actual, 'Adding CONTACT...');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -72,7 +70,11 @@ describe('setupI18n', () => {
|
|||
|
||||
describe('isLegacyFormat', () => {
|
||||
it('returns false for new format', () => {
|
||||
assert.isFalse(i18n.isLegacyFormat('icu:ProfileEditor--info'));
|
||||
assert.isFalse(
|
||||
i18n.isLegacyFormat(
|
||||
'icu:AddUserToAnotherGroupModal__toast--adding-user-to-group'
|
||||
)
|
||||
);
|
||||
assert.isTrue(i18n.isLegacyFormat('softwareAcknowledgments'));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@ export const getMaximumAttachmentSizeInKb = (
|
|||
};
|
||||
|
||||
export function getRenderDetailsForLimit(limitKb: number): {
|
||||
limit: string;
|
||||
limit: number;
|
||||
units: string;
|
||||
} {
|
||||
const units = ['kB', 'MB', 'GB'];
|
||||
|
@ -40,7 +40,7 @@ export function getRenderDetailsForLimit(limitKb: number): {
|
|||
} while (limit >= KIBIBYTE && u < units.length - 1);
|
||||
|
||||
return {
|
||||
limit: limit.toFixed(0),
|
||||
limit: Math.trunc(limit),
|
||||
units: units[u],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -166,13 +166,13 @@ export function formatTime(
|
|||
|
||||
if (diff < HOUR) {
|
||||
return i18n('icu:minutesAgo', {
|
||||
minutes: Math.floor(diff / MINUTE).toString(),
|
||||
minutes: Math.floor(diff / MINUTE),
|
||||
});
|
||||
}
|
||||
|
||||
if (isRelativeTime) {
|
||||
return i18n('icu:hoursAgo', {
|
||||
hours: Math.floor(diff / HOUR).toString(),
|
||||
hours: Math.floor(diff / HOUR),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue