From 833db81897d198c4e8ffdec230dcba4bf0e21401 Mon Sep 17 00:00:00 2001 From: zubiden <19638254+zubiden@users.noreply.github.com> Date: Tue, 11 Nov 2025 14:37:48 +0100 Subject: [PATCH] Invite via Link: Use new translations (#6451) --- src/assets/localization/fallback.strings | 15 +++ .../InviteViaLinkModal.module.scss | 7 - .../inviteViaLink/InviteViaLinkModal.tsx | 120 ++++++++---------- src/types/language.d.ts | 22 ++++ 4 files changed, 93 insertions(+), 71 deletions(-) diff --git a/src/assets/localization/fallback.strings b/src/assets/localization/fallback.strings index 2ff807534..3ff64fefb 100644 --- a/src/assets/localization/fallback.strings +++ b/src/assets/localization/fallback.strings @@ -2315,4 +2315,19 @@ "UserNoteHint" = "only visible to you"; "EditUserNoteHint" = "Notes are only visible to you."; "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."; diff --git a/src/components/modals/inviteViaLink/InviteViaLinkModal.module.scss b/src/components/modals/inviteViaLink/InviteViaLinkModal.module.scss index cb9aa59df..9c4249017 100644 --- a/src/components/modals/inviteViaLink/InviteViaLinkModal.module.scss +++ b/src/components/modals/inviteViaLink/InviteViaLinkModal.module.scss @@ -4,13 +4,6 @@ align-items: center; } -.closeButton { - position: absolute; - z-index: 1; - top: 0.5rem; - left: 0.5rem; -} - .contentText { color: var(--color-text-secondary); text-align: center !important; diff --git a/src/components/modals/inviteViaLink/InviteViaLinkModal.tsx b/src/components/modals/inviteViaLink/InviteViaLinkModal.tsx index 59e883a22..96606f075 100644 --- a/src/components/modals/inviteViaLink/InviteViaLinkModal.tsx +++ b/src/components/modals/inviteViaLink/InviteViaLinkModal.tsx @@ -1,6 +1,5 @@ -import type { FC } from '../../../lib/teact/teact'; import { - memo, useCallback, + memo, useEffect, useMemo, useState, } from '../../../lib/teact/teact'; @@ -10,16 +9,14 @@ import type { ApiChat } from '../../../api/types'; import type { TabState } from '../../../global/types'; import { getUserFullName } from '../../../global/helpers'; -import { selectChat } from '../../../global/selectors'; +import { selectChat, selectUser } from '../../../global/selectors'; import { partition } from '../../../util/iteratees'; import { MEMO_EMPTY_ARRAY } from '../../../util/memo'; -import renderText from '../../common/helpers/renderText'; +import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; -import useOldLang from '../../../hooks/useOldLang'; import AvatarList from '../../common/AvatarList'; -import Icon from '../../common/icons/Icon'; import PeerPicker from '../../common/pickers/PeerPicker'; import Button from '../../ui/Button'; import Modal from '../../ui/Modal'; @@ -35,14 +32,14 @@ type StateProps = { chat?: ApiChat; }; -const InviteViaLinkModal: FC = ({ +const InviteViaLinkModal = ({ modal, chat, -}) => { +}: OwnProps & StateProps) => { const { sendInviteMessages, closeInviteViaLinkModal, openPremiumModal } = getActions(); const { missingUsers } = modal || {}; - const lang = useOldLang(); + const lang = useLang(); const [selectedMemberIds, setSelectedMemberIds] = useState([]); const userIds = useMemo(() => missingUsers?.map((user) => user.id) || MEMO_EMPTY_ARRAY, [missingUsers]); @@ -52,35 +49,27 @@ const InviteViaLinkModal: FC = ({ return [requirePremiumIds.map((user) => user.id), regularIds.map((user) => user.id)]; }, [missingUsers]); - const invitableWithPremiumIds = useMemo(() => { + const invitableWithPremiumPeers = useMemo(() => { + const global = getGlobal(); return missingUsers?.filter((user) => user.isRequiringPremiumToInvite || user.isRequiringPremiumToMessage) - .map((user) => user.id); + .map((user) => selectUser(global, user.id)) + .filter(Boolean); }, [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(() => { setSelectedMemberIds(selectableIds); }, [selectableIds]); const handleClose = useLastCallback(() => closeInviteViaLinkModal()); - const handleSendInviteLink = useCallback(() => { + const handleSendInviteLink = useLastCallback(() => { sendInviteMessages({ chatId: chat!.id, userIds: selectedMemberIds }); closeInviteViaLinkModal(); - }, [selectedMemberIds, chat]); + }); - const handleOpenPremiumModal = useCallback(() => { + const handleOpenPremiumModal = useLastCallback(() => { openPremiumModal(); - }, []); + }); const canSendInviteLink = useMemo(() => { if (!chat) return undefined; @@ -90,77 +79,80 @@ const InviteViaLinkModal: FC = ({ const inviteSectionText = useMemo(() => { return canSendInviteLink ? 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]); const premiumSectionText = useMemo(() => { - if (!invitableWithPremiumIds?.length || !topListPeers?.length) return undefined; - const prefix = isEveryPremiumBlocksPm ? 'InviteMessagePremiumBlocked' : 'InvitePremiumBlocked'; - let langKey = `${prefix}One`; - let params = [getUserFullName(topListPeers[0])]; - if (invitableWithPremiumIds.length === 2) { - 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(), - ]; + if (!invitableWithPremiumPeers?.length) return undefined; + if (invitableWithPremiumPeers.length === 1) { + return lang('InviteRestrictedPremiumReasonSingle', { user: getUserFullName(invitableWithPremiumPeers[0]) }, { + withMarkdown: true, + withNodes: true, + }); } - return lang(langKey, params, undefined, topListPeers.length); - }, [invitableWithPremiumIds, isEveryPremiumBlocksPm, lang, topListPeers]); + if (invitableWithPremiumPeers.length <= 3) { + 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); return ( - - {premiumSectionText && ( + {hasPremiumSection && ( <>

- {canSendInviteLink ? lang('InvitePremiumBlockedTitle') : lang('ChannelInviteViaLinkRestricted')} + {canSendInviteLink ? lang('InviteBlockedPremiumTitle') : lang('InviteBlockedNoLinkTitle')}

- {renderText(premiumSectionText, ['simple_markdown'])} + {premiumSectionText}

)} {hasPremiumSection && hasSelectableSection && ( - {lang('InvitePremiumBlockedOr')} + {lang('InviteBlockedOr')} )} {hasSelectableSection && ( @@ -174,7 +166,7 @@ const InviteViaLinkModal: FC = ({ itemIds={userIds} selectedIds={selectedMemberIds} lockedUnselectedIds={unselectableIds} - lockedUnselectedSubtitle={lang('InvitePremiumBlockedUser')} + lockedUnselectedSubtitle={lang('InviteRestrictedPremiumReason')} onSelectedIdsChange={setSelectedMemberIds} isViewOnly={!canSendInviteLink} allowMultiple @@ -187,7 +179,7 @@ const InviteViaLinkModal: FC = ({ onClick={handleSendInviteLink} disabled={!selectedMemberIds.length} > - {lang('SendInviteLink.ActionInvite')} + {lang('InviteViaLinkButton')} )} diff --git a/src/types/language.d.ts b/src/types/language.d.ts index 612098456..fb0318698 100644 --- a/src/types/language.d.ts +++ b/src/types/language.d.ts @@ -1729,6 +1729,15 @@ export interface LangPair { 'UserNoteHint': undefined; 'EditUserNoteHint': undefined; 'AriaStoryTogglerOpen': undefined; + 'InviteBlockedTitle': undefined; + 'InviteBlockedOneMessage': undefined; + 'InviteBlockedManyMessage': undefined; + 'InviteBlockedOr': undefined; + 'InviteBlockedNoLinkTitle': undefined; + 'InviteBlockedPremiumTitle': undefined; + 'InviteBlockedPremiumButton': undefined; + 'InviteRestrictedPremiumReason': undefined; + 'InviteViaLinkButton': undefined; 'StoryUnsupported': undefined; } @@ -2985,6 +2994,12 @@ export interface LangPairWithVariables { 'ActionStarGiftPrepaidUpgraded': { 'user': V; }; + 'InviteRestrictedPremiumReasonSingle': { + 'user': V; + }; + 'InviteRestrictedPremiumReasonMultiple': { + 'list': V; + }; } export interface LangPairPlural { @@ -3334,6 +3349,13 @@ export interface LangPairPluralWithVariables { 'points': V; 'link': V; }; + 'InviteRestrictedUsers': { + 'count': V; + }; + 'InviteRestrictedPremiumReasonMultipleMore': { + 'list': V; + 'count': V; + }; } export type RegularLangKey = keyof LangPair; export type RegularLangKeyWithVariables = keyof LangPairWithVariables;