fix: toast strings are stripped as we don't render html there

pull/3206/head
Audric Ackermann 8 months ago
parent f7b21ab262
commit b48bfef58d

@ -30,7 +30,11 @@
"adminRemoveAsAdmin": "Remove as Admin",
"adminRemoveCommunityNone": "There are no Admins in this Community.",
"adminRemoveFailed": "Failed to remove {name} as Admin.",
"adminRemoveFailedMultiple": "Failed to remove {name} and {count} others as Admin.",
"adminRemoveFailedOther": "Failed to remove {name} and {other_name} as Admin.",
"adminRemovedUser": "<b>{name}</b> was removed as Admin.",
"adminRemovedUserMultiple": "<b>{name}</b> and <b>{count} others</b> were removed as Admin.",
"adminRemovedUserOther": "<b>{name}</b> and <b>{other_name}</b> were removed as Admin.",
"adminSendingPromotion": "Sending admin promotion",
"adminSettings": "Admin Settings",
"adminTwoPromotedToAdmin": "<b>{name}</b> and <b>{other_name}</b> were promoted to Admin.",
@ -67,6 +71,7 @@
"attachmentsDownload": "Download Attachment",
"attachmentsDuration": "Duration:",
"attachmentsErrorLoad": "Error attaching file",
"attachmentsErrorMediaSelection": "Failed to select attachment",
"attachmentsErrorNoApp": "Can't find an app to select media.",
"attachmentsErrorNotSupported": "This file type is not supported.",
"attachmentsErrorNumber": "Unable to send more than 32 image and video files at once.",
@ -143,7 +148,7 @@
"callsPermissionsRequiredDescription": "You can enable the \"Voice and Video Calls\" permission in Privacy Settings.",
"callsReconnecting": "Reconnecting…",
"callsRinging": "Ringing...",
"callsSessionCall": "Session Call",
"callsSessionCall": "{app_name} Call",
"callsSettings": "Calls (Beta)",
"callsVoiceAndVideo": "Voice and Video Calls",
"callsVoiceAndVideoBeta": "Voice and Video Calls (Beta)",
@ -243,7 +248,7 @@
"create": "Create",
"cut": "Cut",
"databaseErrorGeneric": "A database error occurred.<br/><br/>Export your application logs to share for troubleshooting. If this is unsuccessful, reinstall {app_name} and restore your account.<br/><br/>Warning: This will result in loss of all messages, attachments, and account data older than two weeks.",
"databaseErrorTimeout": "We've noticed {app_name} is taking a long time to start.<br/><br/>You can continue to wait, export your device logs to share for troubleshooting, or try restarting Session.",
"databaseErrorTimeout": "We've noticed {app_name} is taking a long time to start.<br/><br/>You can continue to wait, export your device logs to share for troubleshooting, or try restarting {app_name}.",
"databaseErrorUpdate": "Your app database is incompatible with this version of {app_name}. Reinstall the app and restore your account to generate a new database and continue using {app_name}.<br/><br/>Warning: This will result in the loss of all messages and attachments older than two weeks.",
"databaseOptimizing": "Optimizing Database",
"debugLog": "Debug Log",
@ -261,6 +266,8 @@
"deleteAfterLegacyDisappearingMessagesLegacy": "Legacy",
"deleteAfterLegacyDisappearingMessagesOriginal": "Original version of disappearing messages.",
"deleteAfterLegacyDisappearingMessagesTheyChangedTimer": "<b>{name}</b> set the disappearing message timer to <b>{time}</b>",
"deleteAfterLegacyGroupsGroupCreation": "Please wait while the group is created...",
"deleteAfterLegacyGroupsGroupUpdateErrorTitle": "Failed to Update Group",
"deleteMessage": "Delete Message",
"deleteMessageConfirm": "Are you sure you want to delete this message?",
"deleteMessageDeleted": "Message deleted",
@ -325,27 +332,27 @@
"downloading": "Downloading...",
"draft": "Draft",
"edit": "Edit",
"emojiAndSymbols": "Emoji & Symbols",
"emojiAndSymbols": "Emoji and Symbols",
"emojiCategoryActivities": "Activities",
"emojiCategoryAnimals": "Animals & Nature",
"emojiCategoryAnimals": "Animals and Nature",
"emojiCategoryFlags": "Flags",
"emojiCategoryFood": "Food & Drink",
"emojiCategoryFood": "Food and Drink",
"emojiCategoryObjects": "Objects",
"emojiCategoryRecentlyUsed": "Recently Used",
"emojiCategorySmileys": "Smileys & People",
"emojiCategorySmileys": "Smileys and People",
"emojiCategorySymbols": "Symbols",
"emojiCategoryTravel": "Travel & Places",
"emojiCategoryTravel": "Travel and Places",
"emojiReactsClearAll": "Are you sure you want to clear all {emoji}?",
"emojiReactsCoolDown": "Slow down! You've sent too many emoji reacts. Try again soon",
"emojiReactsCountOthers": "{count, plural, one {And # other has reacted {emoji} to this message.} other {And # others have reacted {emoji} to this message.}}",
"emojiReactsHoverNameDesktop": "{name} reacted with <emoji/>",
"emojiReactsHoverTwoNameDesktop": "{name} & {other_name} reacted with <emoji/>",
"emojiReactsHoverTwoNameDesktop": "{name} and {other_name} reacted with <emoji/>",
"emojiReactsHoverTwoNameMultipleDesktop": "{name}, {other_name} and <span>{count} others</span> reacted with <emoji/>",
"emojiReactsHoverTwoNameOneDesktop": "{name}, {other_name} and <span>1 other</span> reacted with <emoji/>",
"emojiReactsHoverYouDesktop": "You reacted with <emoji/>",
"emojiReactsHoverYouNameDesktop": "You & {name} reacted with <emoji/>",
"emojiReactsHoverYouNameMultipleDesktop": "You, {name} & <span>{count} others</span> reacted with <emoji/>",
"emojiReactsHoverYouNameOneDesktop": "You, {name} & <span>1 other</span> reacted with <emoji/>",
"emojiReactsHoverYouNameDesktop": "You and {name} reacted with <emoji/>",
"emojiReactsHoverYouNameMultipleDesktop": "You, {name} and <span>{count} others</span> reacted with <emoji/>",
"emojiReactsHoverYouNameOneDesktop": "You, {name} and <span>1 other</span> reacted with <emoji/>",
"emojiReactsNotification": "Reacted to your message {emoji}",
"enable": "Enable",
"errorConnection": "Please check your internet connection and try again.",
@ -381,8 +388,10 @@
"groupInviteSending": "Sending invite",
"groupInviteSent": "Invite sent",
"groupInviteSuccessful": "Group invite successful",
"groupInviteVersion": "Users must have version {version} or higher to receive invitations",
"groupInviteVersion": "Users must have the latest release to receive invitations",
"groupInviteYou": "<b>You</b> were invited to join the group.",
"groupInviteYouAndMoreNew": "<b>You</b> and <b>{count} others</b> were invited to join the group.",
"groupInviteYouAndOtherNew": "<b>You</b> and <b>{other_name}</b> were invited to join the group.",
"groupLeave": "Leave Group",
"groupLeaveDescription": "Are you sure you want to leave {group_name}?",
"groupLeaveDescriptionAdmin": "Are you sure you want to leave {group_name}? This will deactivate the group for all members.",
@ -392,7 +401,7 @@
"groupMemberLeftMore": "<b>{name}</b> and <b>{count} others</b> left the group.",
"groupMemberLeftTwo": "<b>{name}</b> and <b>{other_name}</b> left the group.",
"groupMemberMoreNew": "<b>{name}</b> and <b>{count} others</b> joined the group.",
"groupMemberNew": "<b>{name}</b> joined the group.",
"groupMemberNew": "<b>{name}</b> was invited to join the group.",
"groupMemberNewHistory": "<b>{name}</b> was invited to join the group. Chat history was shared.",
"groupMemberNewHistoryMultiple": "<b>{name}</b> and <b>{count} others</b> were invited to join the group. Chat history was shared.",
"groupMemberNewHistoryTwo": "<b>{name}</b> and <b>{other_name}</b> were invited to join the group. Chat history was shared.",
@ -401,12 +410,11 @@
"groupMemberNewYouHistory": " <b>{name}</b> was invited to join the group. Chat history was shared.",
"groupMemberNewYouHistoryMultiple": "<b>You</b> and <b>{count} others</b> were invited to join the group. Chat history was shared.",
"groupMemberNewYouHistoryTwo": "<b>You</b> and <b>{name}</b> were invited to join the group. Chat history was shared.",
"groupMemberNewYouMultiple": "<b>You</b> and <b>{count} others</b> were invited to join the group.",
"groupMemberNewYouTwo": "<b>You</b> and <b>{name}</b> were invited to join the group.",
"groupMemberNewYouMultiple": "<b>You</b> and <b>{count} others</b> joined the group.",
"groupMemberNewYouOther": "<b>You</b> and <b>{other_name}</b> joined the group.",
"groupMemberTwoNew": "<b>{name}</b> and <b>{other_name}</b> joined the group.",
"groupMemberYouAndMoreNew": "<b>You</b> and <b>{count} others</b> joined the group.",
"groupMemberYouAndOtherNew": "<b>You</b> and <b>{other_name}</b> joined the group.",
"groupMemberYouLeft": "<b>You</b> left the group.",
"groupMemberYouNew": "<b>You</b> joined the group.",
"groupMembers": "Group Members",
"groupMembersNone": "There are no other members in this group.",
"groupName": "Group Name",
@ -582,8 +590,8 @@
"onboardingAccountCreate": "Create account",
"onboardingAccountCreated": "Account Created",
"onboardingAccountExists": "I have an account",
"onboardingBackAccountCreation": "You cannot go back further. In order to cancel your account creation, Session needs to quit.",
"onboardingBackLoadAccount": "You cannot go back further. In order to stop loading your account, Session needs to quit.",
"onboardingBackAccountCreation": "You cannot go back further. In order to cancel your account creation, {app_name} needs to quit.",
"onboardingBackLoadAccount": "You cannot go back further. In order to stop loading your account, {app_name} needs to quit.",
"onboardingBubbleCreatingAnAccountIsEasy": "Creating an account is instant, free, and anonymous ",
"onboardingBubbleNoPhoneNumber": "You don't even need a phone number to sign up.",
"onboardingBubblePrivacyInYourPocket": "Privacy in your pocket.",
@ -670,6 +678,7 @@
"recoveryPasswordBannerTitle": "Save your recovery password",
"recoveryPasswordDescription": "Use your recovery password to load your account on new devices.<br/><br/>Your account cannot be recovered without your recovery password. Make sure it's stored somewhere safe and secure — and don't share it with anyone.",
"recoveryPasswordEnter": "Enter your recovery password",
"recoveryPasswordErrorLoad": "An error occurred when trying to load your recovery password.<br/><br/>Please export your logs, then upload the file though Session's Help Desk to help resolve this issue.",
"recoveryPasswordErrorMessageGeneric": "Please check your recovery password and try again.",
"recoveryPasswordErrorMessageIncorrect": "Some of the words in your Recovery Password are incorrect. Please check and try again.",
"recoveryPasswordErrorMessageShort": "The Recovery Password you entered is not long enough. Please check and try again.",
@ -729,7 +738,7 @@
"set": "Set",
"settingsRestartDescription": "You must restart {app_name} to apply your new settings.",
"share": "Share",
"shareAccountIdDescription": "Invite your friend to chat with you on Session by sharing your Account ID with them.",
"shareAccountIdDescription": "Invite your friend to chat with you on {app_name} by sharing your Account ID with them.",
"shareAccountIdDescriptionCopied": "Share with your friends wherever you usually speak with them — then move the conversation here.",
"shareExtensionDatabaseError": "There is an issue opening the database. Please restart the app and try again.",
"shareToSession": "Share to {app_Name}",
@ -771,4 +780,4 @@
"window": "Window",
"yes": "Yes",
"you": "You"
}
}

@ -17,7 +17,6 @@ export const SessionHtmlRenderer = ({ tag = 'div', key, html, className }: Recei
return createElement(tag, {
key,
className,
dangerouslySetInnerHTML: { __html: clean },
});
};

@ -398,7 +398,7 @@ export class SessionConversation extends Component<Props, State> {
});
if (blob.blob.size > MAX_ATTACHMENT_FILESIZE_BYTES) {
ToastUtils.pushFileSizeErrorAsByte(MAX_ATTACHMENT_FILESIZE_BYTES);
ToastUtils.pushFileSizeErrorAsByte();
return;
}
} catch (error) {

@ -291,7 +291,7 @@ export class SessionRecording extends Component<Props, State> {
// Is the audio file > attachment filesize limit
if (this.audioBlobMp3.size > MAX_ATTACHMENT_FILESIZE_BYTES) {
ToastUtils.pushFileSizeErrorAsByte(MAX_ATTACHMENT_FILESIZE_BYTES);
ToastUtils.pushFileSizeErrorAsByte();
return;
}

@ -50,8 +50,11 @@ export const AddModeratorsDialog = (props: Props) => {
ToastUtils.pushFailedToAddAsModerator();
} else {
const userDisplayName =
getConversationController().get(pubkey.key)?.getNicknameOrRealUsernameOrPlaceholder() ||
window.i18n('unknown');
window?.log?.info(`${pubkey.key} added as moderator...`);
ToastUtils.pushUserAddedToModerators();
ToastUtils.pushUserAddedToModerators(userDisplayName);
// clear input box
setInputBoxValue('');

@ -25,22 +25,27 @@ async function removeMods(convoId: string, modsToRemove: Array<string>) {
return false;
}
window?.log?.info(`asked to remove moderators: ${modsToRemove}`);
const modsToRemovePubkey = compact(modsToRemove.map(m => PubKey.from(m)));
const modsToRemoveNames = modsToRemovePubkey.map(
m =>
getConversationController().get(m.key)?.getNicknameOrRealUsernameOrPlaceholder() ||
window.i18n('unknown')
);
try {
const convo = getConversationController().get(convoId);
const roomInfos = convo.toOpenGroupV2();
const modsToRemovePubkey = compact(modsToRemove.map(m => PubKey.from(m)));
const res = await sogsV3RemoveAdmins(modsToRemovePubkey, roomInfos);
if (!res) {
window?.log?.warn('failed to remove moderators:', res);
ToastUtils.pushFailedToRemoveFromModerator();
ToastUtils.pushFailedToRemoveFromModerator(modsToRemoveNames);
return false;
}
window?.log?.info(`${modsToRemove} removed from moderators...`);
ToastUtils.pushUserRemovedFromModerators();
ToastUtils.pushUserRemovedFromModerators(modsToRemoveNames);
return true;
} catch (e) {
window?.log?.error('Got error while removing moderator:', e);

@ -78,10 +78,10 @@ export async function removeSenderFromModerator(sender: string, convoId: string)
if (!res) {
window?.log?.warn('failed to remove moderator:', res);
ToastUtils.pushFailedToRemoveFromModerator(userDisplayName);
ToastUtils.pushFailedToRemoveFromModerator([userDisplayName]);
} else {
window?.log?.info(`${pubKeyToRemove.key} removed from moderators...`);
ToastUtils.pushUserRemovedFromModerators(userDisplayName);
ToastUtils.pushUserRemovedFromModerators([userDisplayName]);
}
} catch (e) {
window?.log?.error('Got error while removing moderator:', e);

@ -89,9 +89,9 @@ export function getJoinedGroupUpdateChangeStr(
case 0:
return getString('groupMemberNew', { name: window.i18n('you') });
case 1:
return getString('groupMemberYouAndOtherNew', { other_name: othersNames[0] });
return getString('groupMemberNewYouOther', { other_name: othersNames[0] });
default:
return getString('groupMemberYouAndMoreNew', { count: othersNames.length });
return getString('groupMemberNewYouMultiple', { count: othersNames.length });
}
}
switch (others.length) {

@ -35,6 +35,12 @@ export function pushToastInfo(
);
}
/**
* We are rendering a toast. A toast is only rendering a string and no html at all.
* We have to strip the html tags from the strings we are given.
*/
const getStrippedI18n = window.i18n.stripped;
export function pushToastSuccess(id: string, title: string, description?: string) {
toast.success(
<SessionToast title={title} description={description} type={SessionToastType.Success} />,
@ -44,84 +50,72 @@ export function pushToastSuccess(id: string, title: string, description?: string
export function pushLoadAttachmentFailure(message?: string) {
if (message) {
pushToastError('unableToLoadAttachment', `${window.i18n('attachmentsErrorLoad')} ${message}`);
pushToastError(
'unableToLoadAttachment',
`${getStrippedI18n('attachmentsErrorLoad')} ${message}`
);
} else {
pushToastError('unableToLoadAttachment', window.i18n('attachmentsErrorLoad'));
pushToastError('unableToLoadAttachment', getStrippedI18n('attachmentsErrorLoad'));
}
}
export function pushFileSizeError(limit: number, units: string) {
pushToastError(
'fileSizeWarning',
window.i18n('attachmentsErrorSize'),
`Max size: ${limit} ${units}`
);
}
export function pushFileSizeErrorAsByte(bytesCount: number) {
const units = ['kB', 'MB', 'GB'];
let u = -1;
let limit = bytesCount;
do {
limit /= 1000;
u += 1;
} while (limit >= 1000 && u < units.length - 1);
pushFileSizeError(limit, units[u]);
export function pushFileSizeErrorAsByte() {
pushToastError('fileSizeWarning', getStrippedI18n('attachmentsErrorSize'));
}
export function pushMultipleNonImageError() {
pushToastError('cannotMixImageAndNonImageAttachments', window.i18n('attachmentsErrorTypes'));
pushToastError('attachmentsErrorTypes', getStrippedI18n('attachmentsErrorTypes'));
}
export function pushCannotMixError() {
pushToastError('oneNonImageAtATimeToast', window.i18n('attachmentsErrorTypes'));
pushToastError('attachmentsErrorTypes', getStrippedI18n('attachmentsErrorTypes'));
}
export function pushMaximumAttachmentsError() {
pushToastError('maximumAttachments', window.i18n('attachmentsErrorNumber'));
pushToastError('attachmentsErrorNumber', getStrippedI18n('attachmentsErrorNumber'));
}
export function pushCopiedToClipBoard() {
pushToastInfo('copiedToClipboard', window.i18n('copied'));
pushToastInfo('copiedToClipboard', getStrippedI18n('copied'));
}
export function pushRestartNeeded() {
pushToastInfo('restartNeeded', window.i18n('settingsRestartDescription'));
pushToastInfo('restartNeeded', getStrippedI18n('settingsRestartDescription'));
}
export function pushAlreadyMemberOpenGroup() {
pushToastInfo('publicChatExists', window.i18n('communityJoinedAlready'));
pushToastInfo('publicChatExists', getStrippedI18n('communityJoinedAlready'));
}
export function pushUserBanSuccess() {
pushToastSuccess('userBanned', window.i18n('banUserBanned'));
pushToastSuccess('userBanned', getStrippedI18n('banUserBanned'));
}
export function pushUserBanFailure() {
pushToastError('userBanFailed', window.i18n('banErrorFailed'));
pushToastError('userBanFailed', getStrippedI18n('banErrorFailed'));
}
export function pushUserUnbanSuccess() {
pushToastSuccess('userUnbanned', window.i18n('banUnbanUserUnbanned'));
pushToastSuccess('userUnbanned', getStrippedI18n('banUnbanUserUnbanned'));
}
export function pushUserUnbanFailure() {
pushToastError('userUnbanFailed', window.i18n('banUnbanErrorFailed'));
pushToastError('userUnbanFailed', getStrippedI18n('banUnbanErrorFailed'));
}
export function pushMessageDeleteForbidden() {
pushToastError(
'messageDeletionForbidden',
window.i18n('deleteafterMessageDeletionStandardisationmessageDeletionForbidden')
getStrippedI18n('deleteafterMessageDeletionStandardisationmessageDeletionForbidden')
);
}
export function pushUnableToCall() {
pushToastError('unableToCall', window.i18n('callsCannotStart'), window.i18n('callsCannotStart'));
pushToastError('unableToCall', getStrippedI18n('callsCannotStart'));
}
export function pushedMissedCall(conversationName: string) {
pushToastInfo('missedCall', window.i18n('callsMissedCallFrom', { name: conversationName }));
export function pushedMissedCall(userName: string) {
pushToastInfo('missedCall', getStrippedI18n('callsMissedCallFrom', { name: userName }));
}
const openPermissionsSettings = () => {
@ -133,8 +127,8 @@ export function pushedMissedCallCauseOfPermission(conversationName: string) {
const id = 'missedCallPermission';
toast.info(
<SessionToast
title={window.i18n('callsMissedCallFrom', { name: conversationName })}
description={window.i18n('callsYouMissedCallPermissions', { name: conversationName })}
title={getStrippedI18n('callsMissedCallFrom', { name: conversationName })}
description={getStrippedI18n('callsYouMissedCallPermissions', { name: conversationName })}
type={SessionToastType.Info}
onToastClick={openPermissionsSettings}
/>,
@ -145,8 +139,8 @@ export function pushedMissedCallCauseOfPermission(conversationName: string) {
export function pushVideoCallPermissionNeeded() {
pushToastInfo(
'videoCallPermissionNeeded',
window.i18n('callsPermissionsRequired'),
window.i18n('callsPermissionsRequiredDescription'),
getStrippedI18n('callsPermissionsRequired'),
getStrippedI18n('callsPermissionsRequiredDescription'),
openPermissionsSettings
);
}
@ -154,83 +148,123 @@ export function pushVideoCallPermissionNeeded() {
export function pushAudioPermissionNeeded() {
pushToastInfo(
'audioPermissionNeeded',
window.i18n('permissionsMicrophoneAccessRequiredDesktop'),
getStrippedI18n('permissionsMicrophoneAccessRequiredDesktop'),
undefined,
openPermissionsSettings
);
}
export function pushOriginalNotFound() {
pushToastError('originalMessageNotFound', window.i18n('messageErrorOriginal'));
pushToastError('messageErrorOriginal', getStrippedI18n('messageErrorOriginal'));
}
export function pushTooManyMembers() {
pushToastError('tooManyMembers', window.i18n('groupAddMemberMaximum'));
pushToastError('groupAddMemberMaximum', getStrippedI18n('groupAddMemberMaximum'));
}
export function pushMessageRequestPending() {
pushToastInfo('messageRequestPending', window.i18n('messageRequestPending'));
pushToastInfo('messageRequestPending', getStrippedI18n('messageRequestPending'));
}
export function pushUnblockToSend() {
pushToastInfo('unblockToSend', window.i18n('blockBlockedDescription'));
pushToastInfo('unblockToSend', getStrippedI18n('blockBlockedDescription'));
}
export function pushYouLeftTheGroup() {
pushToastError('youLeftTheGroup', window.i18n('groupMemberYouLeft'));
pushToastError('youLeftTheGroup', getStrippedI18n('groupMemberYouLeft'));
}
export function someDeletionsFailed() {
pushToastWarning('deletionError', 'Deletion error');
export function someDeletionsFailed(count: number) {
pushToastWarning('deletionError', getStrippedI18n('deleteMessagesFailed', { count }));
}
export function pushDeleted() {
pushToastSuccess('deleted', window.i18n('deleteMessagesDeleted'), undefined);
pushToastSuccess('deleted', getStrippedI18n('deleteMessagesDeleted'), undefined);
}
export function pushCannotRemoveCreatorFromGroup() {
pushToastWarning('adminCannotBeRemoved', window.i18n('adminCannotBeRemoved'));
pushToastWarning('adminCannotBeRemoved', getStrippedI18n('adminCannotBeRemoved'));
}
export function pushFailedToAddAsModerator() {
pushToastWarning('adminPromotionFailed', window.i18n('adminPromotionFailed'));
}
export function pushFailedToRemoveFromModerator(name: string) {
pushToastWarning(
'adminRemoveFailed',
window.i18n('adminRemoveFailed', {
name,
})
);
pushToastWarning('adminPromotionFailed', getStrippedI18n('adminPromotionFailed'));
}
export function pushFailedToRemoveFromModerator(names: Array<string>) {
let localizedString: string = '';
switch (names.length) {
case 0:
throw new Error('pushFailedToRemoveFromModerator invalid case error');
case 1:
localizedString = getStrippedI18n('adminRemoveFailed', {
name: names[0],
});
break;
case 2:
localizedString = getStrippedI18n('adminRemoveFailedOther', {
name: names[0],
other_name: names[1],
});
break;
default:
localizedString = getStrippedI18n('adminRemoveFailedMultiple', {
name: names[0],
count: names.length - 1,
});
break;
}
pushToastWarning('adminRemoveFailed', localizedString);
}
export function pushUserAddedToModerators(name: string) {
pushToastSuccess('adminPromotedToAdmin', window.i18n('adminPromotedToAdmin', { name }));
}
pushToastSuccess('adminPromotedToAdmin', getStrippedI18n('adminPromotedToAdmin', { name }));
}
export function pushUserRemovedFromModerators(names: Array<string>) {
let localizedString: string = '';
switch (names.length) {
case 0:
throw new Error('pushUserRemovedFromModerators invalid case error');
case 1:
localizedString = getStrippedI18n('adminRemovedUser', {
name: names[0],
});
break;
case 2:
localizedString = getStrippedI18n('adminRemovedUserOther', {
name: names[0],
other_name: names[1],
});
break;
default:
localizedString = getStrippedI18n('adminRemovedUserMultiple', {
name: names[0],
count: names.length - 1,
});
break;
}
export function pushUserRemovedFromModerators(name: string) {
pushToastSuccess('adminRemovedUser', window.i18n('adminRemovedUser', { name }));
pushToastSuccess('adminRemovedUser', localizedString);
}
export function pushInvalidPubKey() {
pushToastSuccess('invalidPubKey', window.i18n('accountIdErrorInvalid'));
pushToastSuccess('accountIdErrorInvalid', getStrippedI18n('accountIdErrorInvalid'));
}
export function pushNoCameraFound() {
pushToastWarning('noCameraFound', window.i18n('cameraErrorNotFound'));
pushToastWarning('noCameraFound', getStrippedI18n('cameraErrorNotFound'));
}
export function pushNoAudioInputFound() {
pushToastWarning('noAudioInputFound', window.i18n('audioNoInput'));
pushToastWarning('noAudioInputFound', getStrippedI18n('audioNoInput'));
}
export function pushNoAudioOutputFound() {
pushToastWarning('noAudioOutputFound', window.i18n('audioNoOutput'));
pushToastWarning('noAudioOutputFound', getStrippedI18n('audioNoOutput'));
}
export function pushNoMediaUntilApproved() {
pushToastError('noMediaUntilApproved', window.i18n('messageRequestPendingDescription'));
pushToastError('noMediaUntilApproved', getStrippedI18n('messageRequestPendingDescription'));
}
export function pushRateLimitHitReactions() {

@ -26,7 +26,6 @@ import { hasValidIncomingRequestValues } from '../../models/conversation';
import { isOpenOrClosedGroup } from '../../models/conversationAttributes';
import { getConversationController } from '../../session/conversations';
import { UserUtils } from '../../session/utils';
import { LocalizerType } from '../../types/Util';
import { BlockedNumberController } from '../../util';
import { Storage } from '../../util/storage';
import { getIntl } from './user';
@ -220,23 +219,20 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
}
);
function getConversationTitle(
conversation: ReduxConversationType,
testingi18n?: LocalizerType
): string {
function getConversationTitle(conversation: ReduxConversationType): string {
if (conversation.displayNameInProfile) {
return conversation.displayNameInProfile;
}
if (isOpenOrClosedGroup(conversation.type)) {
return (testingi18n || window.i18n)('unknown');
return window.i18n('unknown');
}
return conversation.id;
}
const collator = new Intl.Collator();
export const _getConversationComparator = (testingi18n?: LocalizerType) => {
export const _getConversationComparator = () => {
return (left: ReduxConversationType, right: ReduxConversationType): number => {
// Pin is the first criteria to check
const leftPriority = left.priority || 0;
@ -259,8 +255,8 @@ export const _getConversationComparator = (testingi18n?: LocalizerType) => {
if (leftActiveAt && rightActiveAt && leftActiveAt !== rightActiveAt) {
return rightActiveAt - leftActiveAt;
}
const leftTitle = getConversationTitle(left, testingi18n).toLowerCase();
const rightTitle = getConversationTitle(right, testingi18n).toLowerCase();
const leftTitle = getConversationTitle(left).toLowerCase();
const rightTitle = getConversationTitle(right).toLowerCase();
return collator.compare(leftTitle, rightTitle);
};

@ -1,22 +1,22 @@
import { assert } from 'chai';
import Sinon from 'sinon';
import { CONVERSATION_PRIORITIES, ConversationTypeEnum } from '../../../../models/types';
import { ConversationLookupType } from '../../../../state/ducks/conversations';
import {
_getConversationComparator,
_getSortedConversations,
} from '../../../../state/selectors/conversations';
import { ConversationTypeEnum, CONVERSATION_PRIORITIES } from '../../../../models/types';
import type {
GetMessageArgs,
LocalizerDictionary,
LocalizerToken,
} from '../../../../types/Localizer';
const i18n = <T extends LocalizerToken, R extends LocalizerDictionary[T]>(
...[token]: GetMessageArgs<T>
) => token as any as R;
import { TestUtils } from '../../../test-utils';
describe('state/selectors/conversations', () => {
beforeEach(() => {
TestUtils.stubWindowLog();
TestUtils.stubI18n();
});
afterEach(() => {
Sinon.restore();
});
describe('#getSortedConversationsList', () => {
it('sorts conversations based on timestamp then by intl-friendly title', () => {
const data: ConversationLookupType = {
@ -138,7 +138,7 @@ describe('state/selectors/conversations', () => {
priority: CONVERSATION_PRIORITIES.default,
},
};
const comparator = _getConversationComparator(i18n);
const comparator = _getConversationComparator();
const conversations = _getSortedConversations(data, comparator);
assert.strictEqual(conversations[0].displayNameInProfile, 'First!');
@ -277,7 +277,7 @@ describe('state/selectors/conversations', () => {
isPublic: false,
},
};
const comparator = _getConversationComparator(i18n);
const comparator = _getConversationComparator();
const conversations = _getSortedConversations(data, comparator);
assert.strictEqual(conversations[0].displayNameInProfile, 'Á');

@ -13,6 +13,9 @@ import {
} from 'date-fns';
import timeLocales from 'date-fns/locale';
import { isUndefined } from 'lodash';
import { GetNetworkTime } from '../session/apis/snode_api/getNetworkTime';
import { DURATION_SECONDS, LOCALE_DEFAULTS } from '../session/constants';
import { updateLocale } from '../state/ducks/dictionary';
import {
DictionaryWithoutPluralStrings,
GetMessageArgs,
@ -21,10 +24,6 @@ import {
PluralKey,
PluralString,
} from '../types/Localizer';
import { DURATION_SECONDS, LOCALE_DEFAULTS } from '../session/constants';
import { updateLocale } from '../state/ducks/dictionary';
import { GetNetworkTime } from '../session/apis/snode_api/getNetworkTime';
import { Dictionary } from '../localization/locales';
export function loadDictionary(locale: Locale) {
return import(`../../_locales/${locale}/messages.json`) as Promise<LocalizerDictionary>;
@ -232,7 +231,7 @@ export const setupi18n = (locale: Locale, dictionary: LocalizerDictionary) => {
return token as R;
}
localizedString = pluralString.replaceAll('#', num) as R;
localizedString = pluralString.replaceAll('#', `${num}`) as R;
}
}

Loading…
Cancel
Save