Invite via Link: Use new translations (#6451)

This commit is contained in:
zubiden 2025-11-11 14:37:48 +01:00 committed by Alexander Zinchuk
parent 9192eb10fe
commit 833db81897
4 changed files with 93 additions and 71 deletions

View File

@ -2315,4 +2315,19 @@
"UserNoteHint" = "only visible to you"; "UserNoteHint" = "only visible to you";
"EditUserNoteHint" = "Notes are only visible to you."; "EditUserNoteHint" = "Notes are only visible to you.";
"AriaStoryTogglerOpen" = "Open Story List"; "AriaStoryTogglerOpen" = "Open Story List";
"InviteBlockedTitle" = "Invite via Link";
"InviteBlockedOneMessage" = "This user restricts adding them to groups. You can send an invite link in a private message instead.";
"InviteBlockedManyMessage" = "Some users restrict adding them to groups. You can send these people an invite link in a private message instead.";
"InviteBlockedOr" = "or";
"InviteBlockedNoLinkTitle" = "You can't create a link";
"InviteBlockedPremiumTitle" = "Upgrade to Premium";
"InviteBlockedPremiumButton" = "Subscribe to Telegram Premium";
"InviteRestrictedPremiumReason" = "available only to Premium users";
"InviteRestrictedUsers_one" = "**{count} user** can only be invited via link, but you don't have permission to share invite links to this group.";
"InviteRestrictedUsers_other" = "**{count} users** can only be invited via link, but you don't have permission to share invite links to this group.";
"InviteViaLinkButton" = "Send Invite Link";
"InviteRestrictedPremiumReasonSingle" = "**{user}** accepts invitations to groups from contacts and **Premium** users.";
"InviteRestrictedPremiumReasonMultiple" = "{list} only accept invitations to groups from contacts and **Premium** users.";
"InviteRestrictedPremiumReasonMultipleMore_one" = "{list} and **{count} more** person only accept invitations to groups from contacts and **Premium** users.";
"InviteRestrictedPremiumReasonMultipleMore_other" = "{list} and **{count} more** people only accept invitations to groups from contacts and **Premium** users.";
"StoryUnsupported" = "This story is not supported in Telegram Web A. Try viewing it in the Telegram app."; "StoryUnsupported" = "This story is not supported in Telegram Web A. Try viewing it in the Telegram app.";

View File

@ -4,13 +4,6 @@
align-items: center; align-items: center;
} }
.closeButton {
position: absolute;
z-index: 1;
top: 0.5rem;
left: 0.5rem;
}
.contentText { .contentText {
color: var(--color-text-secondary); color: var(--color-text-secondary);
text-align: center !important; text-align: center !important;

View File

@ -1,6 +1,5 @@
import type { FC } from '../../../lib/teact/teact';
import { import {
memo, useCallback, memo,
useEffect, useEffect,
useMemo, useState, useMemo, useState,
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
@ -10,16 +9,14 @@ import type { ApiChat } from '../../../api/types';
import type { TabState } from '../../../global/types'; import type { TabState } from '../../../global/types';
import { getUserFullName } from '../../../global/helpers'; import { getUserFullName } from '../../../global/helpers';
import { selectChat } from '../../../global/selectors'; import { selectChat, selectUser } from '../../../global/selectors';
import { partition } from '../../../util/iteratees'; import { partition } from '../../../util/iteratees';
import { MEMO_EMPTY_ARRAY } from '../../../util/memo'; import { MEMO_EMPTY_ARRAY } from '../../../util/memo';
import renderText from '../../common/helpers/renderText';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback'; import useLastCallback from '../../../hooks/useLastCallback';
import useOldLang from '../../../hooks/useOldLang';
import AvatarList from '../../common/AvatarList'; import AvatarList from '../../common/AvatarList';
import Icon from '../../common/icons/Icon';
import PeerPicker from '../../common/pickers/PeerPicker'; import PeerPicker from '../../common/pickers/PeerPicker';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
import Modal from '../../ui/Modal'; import Modal from '../../ui/Modal';
@ -35,14 +32,14 @@ type StateProps = {
chat?: ApiChat; chat?: ApiChat;
}; };
const InviteViaLinkModal: FC<OwnProps & StateProps> = ({ const InviteViaLinkModal = ({
modal, modal,
chat, chat,
}) => { }: OwnProps & StateProps) => {
const { sendInviteMessages, closeInviteViaLinkModal, openPremiumModal } = getActions(); const { sendInviteMessages, closeInviteViaLinkModal, openPremiumModal } = getActions();
const { missingUsers } = modal || {}; const { missingUsers } = modal || {};
const lang = useOldLang(); const lang = useLang();
const [selectedMemberIds, setSelectedMemberIds] = useState<string[]>([]); const [selectedMemberIds, setSelectedMemberIds] = useState<string[]>([]);
const userIds = useMemo(() => missingUsers?.map((user) => user.id) || MEMO_EMPTY_ARRAY, [missingUsers]); const userIds = useMemo(() => missingUsers?.map((user) => user.id) || MEMO_EMPTY_ARRAY, [missingUsers]);
@ -52,35 +49,27 @@ const InviteViaLinkModal: FC<OwnProps & StateProps> = ({
return [requirePremiumIds.map((user) => user.id), regularIds.map((user) => user.id)]; return [requirePremiumIds.map((user) => user.id), regularIds.map((user) => user.id)];
}, [missingUsers]); }, [missingUsers]);
const invitableWithPremiumIds = useMemo(() => { const invitableWithPremiumPeers = useMemo(() => {
const global = getGlobal();
return missingUsers?.filter((user) => user.isRequiringPremiumToInvite || user.isRequiringPremiumToMessage) return missingUsers?.filter((user) => user.isRequiringPremiumToInvite || user.isRequiringPremiumToMessage)
.map((user) => user.id); .map((user) => selectUser(global, user.id))
.filter(Boolean);
}, [missingUsers]); }, [missingUsers]);
const isEveryPremiumBlocksPm = useMemo(() => {
if (!missingUsers) return undefined;
return !missingUsers.some((user) => user.isRequiringPremiumToInvite && !user.isRequiringPremiumToMessage);
}, [missingUsers]);
const topListPeers = useMemo(() => {
const users = getGlobal().users.byId;
return invitableWithPremiumIds?.map((id) => users[id]);
}, [invitableWithPremiumIds]);
useEffect(() => { useEffect(() => {
setSelectedMemberIds(selectableIds); setSelectedMemberIds(selectableIds);
}, [selectableIds]); }, [selectableIds]);
const handleClose = useLastCallback(() => closeInviteViaLinkModal()); const handleClose = useLastCallback(() => closeInviteViaLinkModal());
const handleSendInviteLink = useCallback(() => { const handleSendInviteLink = useLastCallback(() => {
sendInviteMessages({ chatId: chat!.id, userIds: selectedMemberIds }); sendInviteMessages({ chatId: chat!.id, userIds: selectedMemberIds });
closeInviteViaLinkModal(); closeInviteViaLinkModal();
}, [selectedMemberIds, chat]); });
const handleOpenPremiumModal = useCallback(() => { const handleOpenPremiumModal = useLastCallback(() => {
openPremiumModal(); openPremiumModal();
}, []); });
const canSendInviteLink = useMemo(() => { const canSendInviteLink = useMemo(() => {
if (!chat) return undefined; if (!chat) return undefined;
@ -90,77 +79,80 @@ const InviteViaLinkModal: FC<OwnProps & StateProps> = ({
const inviteSectionText = useMemo(() => { const inviteSectionText = useMemo(() => {
return canSendInviteLink return canSendInviteLink
? lang(missingUsers?.length === 1 ? 'InviteBlockedOneMessage' : 'InviteBlockedManyMessage') ? lang(missingUsers?.length === 1 ? 'InviteBlockedOneMessage' : 'InviteBlockedManyMessage')
: lang('InviteRestrictedUsers2', missingUsers?.length); : lang('InviteRestrictedUsers', { count: missingUsers?.length }, {
pluralValue: missingUsers?.length || 0,
withMarkdown: true,
withNodes: true,
});
}, [canSendInviteLink, lang, missingUsers?.length]); }, [canSendInviteLink, lang, missingUsers?.length]);
const premiumSectionText = useMemo(() => { const premiumSectionText = useMemo(() => {
if (!invitableWithPremiumIds?.length || !topListPeers?.length) return undefined; if (!invitableWithPremiumPeers?.length) return undefined;
const prefix = isEveryPremiumBlocksPm ? 'InviteMessagePremiumBlocked' : 'InvitePremiumBlocked'; if (invitableWithPremiumPeers.length === 1) {
let langKey = `${prefix}One`; return lang('InviteRestrictedPremiumReasonSingle', { user: getUserFullName(invitableWithPremiumPeers[0]) }, {
let params = [getUserFullName(topListPeers[0])]; withMarkdown: true,
if (invitableWithPremiumIds.length === 2) { withNodes: true,
langKey = `${prefix}Two`; });
params = [getUserFullName(topListPeers[0]), getUserFullName(topListPeers[1])];
} else if (invitableWithPremiumIds.length === 3) {
langKey = `${prefix}Three`;
params = [getUserFullName(topListPeers[0]), getUserFullName(topListPeers[1]), getUserFullName(topListPeers[2])];
} else if (invitableWithPremiumIds.length > 3) {
langKey = `${prefix}Many`;
params = [
getUserFullName(topListPeers[0]),
getUserFullName(topListPeers[1]),
(invitableWithPremiumIds.length - 2).toString(),
];
} }
return lang(langKey, params, undefined, topListPeers.length); if (invitableWithPremiumPeers.length <= 3) {
}, [invitableWithPremiumIds, isEveryPremiumBlocksPm, lang, topListPeers]); const list = lang.conjunction(invitableWithPremiumPeers.map((peer) => getUserFullName(peer)).filter(Boolean));
return lang('InviteRestrictedPremiumReasonMultiple', { list }, {
withMarkdown: true,
withNodes: true,
});
}
const hasPremiumSection = Boolean(topListPeers?.length); if (invitableWithPremiumPeers.length > 3) {
const moreCount = invitableWithPremiumPeers.length - 2;
const peers = invitableWithPremiumPeers.slice(0, 2);
const list = lang.conjunction(peers.map((peer) => getUserFullName(peer)).filter(Boolean));
return lang('InviteRestrictedPremiumReasonMultipleMore', { list, count: moreCount }, {
pluralValue: moreCount,
withMarkdown: true,
withNodes: true,
});
}
return undefined;
}, [invitableWithPremiumPeers, lang]);
const hasPremiumSection = Boolean(invitableWithPremiumPeers?.length);
const hasSelectableSection = Boolean(selectableIds?.length); const hasSelectableSection = Boolean(selectableIds?.length);
return ( return (
<Modal <Modal
isOpen={Boolean(userIds && chat)} isOpen={Boolean(userIds && chat)}
contentClassName={styles.content} contentClassName={styles.content}
hasAbsoluteCloseButton
onClose={handleClose} onClose={handleClose}
isSlim isSlim
> >
<Button {hasPremiumSection && (
round
color="translucent"
size="smaller"
className={styles.closeButton}
ariaLabel={lang('Close')}
onClick={handleClose}
>
<Icon name="close" />
</Button>
{premiumSectionText && (
<> <>
<AvatarList <AvatarList
className={styles.avatarList} className={styles.avatarList}
peers={topListPeers} peers={invitableWithPremiumPeers}
size="large" size="large"
/> />
<h3 className={styles.title}> <h3 className={styles.title}>
{canSendInviteLink ? lang('InvitePremiumBlockedTitle') : lang('ChannelInviteViaLinkRestricted')} {canSendInviteLink ? lang('InviteBlockedPremiumTitle') : lang('InviteBlockedNoLinkTitle')}
</h3> </h3>
<p className={styles.contentText}> <p className={styles.contentText}>
{renderText(premiumSectionText, ['simple_markdown'])} {premiumSectionText}
</p> </p>
<Button <Button
withPremiumGradient withPremiumGradient
isShiny isShiny
onClick={handleOpenPremiumModal} onClick={handleOpenPremiumModal}
> >
{lang('InvitePremiumBlockedSubscribe')} {lang('InviteBlockedPremiumButton')}
</Button> </Button>
</> </>
)} )}
{hasPremiumSection && hasSelectableSection && ( {hasPremiumSection && hasSelectableSection && (
<Separator className={styles.separator}> <Separator className={styles.separator}>
{lang('InvitePremiumBlockedOr')} {lang('InviteBlockedOr')}
</Separator> </Separator>
)} )}
{hasSelectableSection && ( {hasSelectableSection && (
@ -174,7 +166,7 @@ const InviteViaLinkModal: FC<OwnProps & StateProps> = ({
itemIds={userIds} itemIds={userIds}
selectedIds={selectedMemberIds} selectedIds={selectedMemberIds}
lockedUnselectedIds={unselectableIds} lockedUnselectedIds={unselectableIds}
lockedUnselectedSubtitle={lang('InvitePremiumBlockedUser')} lockedUnselectedSubtitle={lang('InviteRestrictedPremiumReason')}
onSelectedIdsChange={setSelectedMemberIds} onSelectedIdsChange={setSelectedMemberIds}
isViewOnly={!canSendInviteLink} isViewOnly={!canSendInviteLink}
allowMultiple allowMultiple
@ -187,7 +179,7 @@ const InviteViaLinkModal: FC<OwnProps & StateProps> = ({
onClick={handleSendInviteLink} onClick={handleSendInviteLink}
disabled={!selectedMemberIds.length} disabled={!selectedMemberIds.length}
> >
{lang('SendInviteLink.ActionInvite')} {lang('InviteViaLinkButton')}
</Button> </Button>
)} )}
</> </>

View File

@ -1729,6 +1729,15 @@ export interface LangPair {
'UserNoteHint': undefined; 'UserNoteHint': undefined;
'EditUserNoteHint': undefined; 'EditUserNoteHint': undefined;
'AriaStoryTogglerOpen': undefined; 'AriaStoryTogglerOpen': undefined;
'InviteBlockedTitle': undefined;
'InviteBlockedOneMessage': undefined;
'InviteBlockedManyMessage': undefined;
'InviteBlockedOr': undefined;
'InviteBlockedNoLinkTitle': undefined;
'InviteBlockedPremiumTitle': undefined;
'InviteBlockedPremiumButton': undefined;
'InviteRestrictedPremiumReason': undefined;
'InviteViaLinkButton': undefined;
'StoryUnsupported': undefined; 'StoryUnsupported': undefined;
} }
@ -2985,6 +2994,12 @@ export interface LangPairWithVariables<V = LangVariable> {
'ActionStarGiftPrepaidUpgraded': { 'ActionStarGiftPrepaidUpgraded': {
'user': V; 'user': V;
}; };
'InviteRestrictedPremiumReasonSingle': {
'user': V;
};
'InviteRestrictedPremiumReasonMultiple': {
'list': V;
};
} }
export interface LangPairPlural { export interface LangPairPlural {
@ -3334,6 +3349,13 @@ export interface LangPairPluralWithVariables<V = LangVariable> {
'points': V; 'points': V;
'link': V; 'link': V;
}; };
'InviteRestrictedUsers': {
'count': V;
};
'InviteRestrictedPremiumReasonMultipleMore': {
'list': V;
'count': V;
};
} }
export type RegularLangKey = keyof LangPair; export type RegularLangKey = keyof LangPair;
export type RegularLangKeyWithVariables = keyof LangPairWithVariables; export type RegularLangKeyWithVariables = keyof LangPairWithVariables;