diff --git a/src/assets/localization/fallback.strings b/src/assets/localization/fallback.strings index d30141abb..96911a9dd 100644 --- a/src/assets/localization/fallback.strings +++ b/src/assets/localization/fallback.strings @@ -76,6 +76,7 @@ "PremiumLimitAccountsNoPremium" = "You have reached your current limit of connected accounts. You can free one more place by subscribing to Telegram Premium."; "PremiumLimitAccounts" = "You have reached your current limit of connected accounts. You can free one more place by subscribing to Telegram Premium with one of these connected accounts."; "SendMessage" = "Send Message"; +"MessageUnsupported" = "This message is not supported on the web version of Telegram"; "ConversationDefaultRestrictedMedia" = "Sending media isn't allowed in this group."; "AccDescrVoiceMessage" = "Record voice message"; "BotSettings" = "Settings"; @@ -87,7 +88,7 @@ "ContextCopySelected" = "Copy Selected Text"; "ContextCopyText" = "Copy Text"; "ContextArchiveCollapse" = "Collapse"; -"ContextArchiveExpand" = "Collapse"; +"ContextArchiveExpand" = "Expand"; "ContextArchiveToMenu" = "Move to Main Menu"; "CallMessageVideoIncomingDeclined" = "Declined Video Call"; "CallMessageVideoOutgoingMissed" = "Canceled Video Call"; @@ -129,6 +130,7 @@ "UserRestrictionsNoChangeInfo" = "can't change Info"; "UserRestrictionsInviteUsers" = "Add Users"; "UserRestrictionsPinMessages" = "Pin Messages"; +"ChatPermissionNotAvailable" = "This permission is not available in public groups."; "StatsMessageInteractionsTitle" = "INTERACTIONS"; "StatsGroupGrowthTitle" = "GROWTH"; "StatsGroupMembersTitle" = "GROUP MEMBERS"; @@ -474,6 +476,7 @@ "AlwaysShareWith" = "Always Share With"; "NeverShareWith" = "Never Share With"; "SessionsTitle" = "Active Sessions"; +"SessionTerminate" = "Terminate"; "OtherWebSessions" = "Connected Websites"; "BlockedUsers" = "Blocked Users"; "TwoStepVerification" = "Two-Step Verification"; @@ -522,7 +525,7 @@ "WhoCanCallMe" = "Who can call me"; "PrivacyP2P" = "Peer-to-Peer Calls"; "PrivacyForwardsTitle" = "Who can add a link to my account when forwarding my messages?"; -"WhoCanAddMe" = "Who can add me to group chats?"; +"WhoCanAddMe" = "Who can add me to groups and channels?"; "NewChatsFromNonContacts" = "New chats from unknown users"; "ArchiveAndMute" = "Archive and Mute"; "ArchiveAndMuteInfo" = "Automatically archive and mute new chats, groups and channels from non-contacts."; @@ -689,6 +692,7 @@ "SettingsPerformanceStickerEffects" = "Sticker Effects"; "SettingsPerformanceAutoplayGif" = "Autoplay GIFs"; "SettingsPerformanceAutoplayVideo" = "Autoplay Videos"; +"SettingsPerformanceGranularTitle" = "Resource-Intensive Processes"; "FavoriteStickers" = "Favorites"; "PremiumStickers" = "Premium Stickers"; "GroupStickers" = "Group Stickers"; @@ -711,7 +715,6 @@ "ErrorUnspecified" = "Error"; "NoStickers" = "No stickers yet"; "ClearRecentEmoji" = "Clear recent emoji?"; -"TextFormatAddLinkTitle" = "Add Link"; "Save" = "Save"; "ConversationEmptyPlaceholder" = "No messages here yet..."; "ConversationGreetingText" = "Send a message or tap on the greeting below."; @@ -957,8 +960,16 @@ "ChannelPermissionsHeader" = "What can members of this group do?"; "UserRestrictionsSend" = "Send Messages"; "UserRestrictionsSendMedia" = "Send Media"; -"UserRestrictionsSendStickers" = "Send Stickers & GIFs"; -"UserRestrictionsSendPolls" = "Send Polls"; +"UserRestrictionsCreateTopics" = "Create Topics"; +"SendMediaPermissionFiles" = "Files"; +"SendMediaPermissionPhotos" = "Photos"; +"SendMediaPermissionVideos" = "Videos"; +"SendMediaPermissionStickersGifs" = "Stickers & GIFs"; +"SendMediaPermissionAudios" = "Music"; +"SendMediaPermissionVoices" = "Voice Messages"; +"SendMediaPermissionRoundVideos" = "Video Messages"; +"SendMediaPermissionWebPages" = "Embed Links"; +"SendMediaPermissionPolls" = "Polls"; "UserRestrictionsEmbedLinks" = "Embed Links"; "UserRestrictionsChangeInfo" = "Change Chat Info"; "ChannelAddException" = "Add Exception"; @@ -1089,12 +1100,14 @@ "ChannelPersmissionDeniedSendMessagesForever" = "The admins of this group have restricted your ability to send messages."; "ChannelPersmissionDeniedSendMessagesDefaultRestrictedText" = "Sending messages is not allowed in this group."; "Chats" = "Chats"; +"ChatsPlural_one" = "{count} chat"; +"ChatsPlural_other" = "{count} chats"; "NewDiscussionChatTitle" = "{name} Chat"; "FilterBots" = "Bots"; "FilterContacts" = "Contacts"; "FilterNonContacts" = "Non-Contacts"; "FromYou" = "You"; -"InDlgAlbum" = "Album"; +"Album" = "Album"; "AttachPhoto" = "Photo"; "AttachGif" = "GIF"; "AttachVideo" = "Video"; @@ -1102,8 +1115,12 @@ "AttachMusic" = "Music"; "AttachContact" = "Contact"; "AttachStory" = "Story"; -"MessageLocation" = "Location"; -"MessageLiveLocation" = "Live Location"; +"AttachInvoice" = "Invoice: {description}"; +"AttachLocation" = "Location"; +"AttachLiveLocation" = "Live Location"; +"AttachGiveaway" = "Giveaway"; +"AttachGiveawayResults" = "Giveaway Results"; +"AttachTodo" = "Checklist"; "ServiceNotifications" = "service notifications"; "Bot" = "bot"; "ALongTimeAgo" = "last seen a long time ago"; @@ -1277,6 +1294,7 @@ "SettingsPasscodeStart1" = "When you set up an additional passcode, a lock icon will appear on the chats page.\nTap it to lock and unlock your Telegram Web A."; "SettingsPasscodeStart2" = "Note: if you forget your local passcode, you'll need to log out of Telegram Web A and log in again."; "CurrentPasswordPlaceholder" = "Current password"; +"ChangeYourProfilePicture" = "Change your profile picture"; "TooManyTabsTitle" = "Such error, many tabs"; "TooManyTabsDescription" = "Telegram supports only one active tab with the app.\nPlease reload this page to continue using this tab or close it."; "TooManyTabsReload" = "Reload app"; @@ -1338,6 +1356,7 @@ "FormattingMonospaceAria" = "Monospace text"; "FormattingUnderlineAria" = "Underlined text"; "FormattingStrikethroughAria" = "Strikethrough text"; +"FormattingAddLinkAria" = "Add Link"; "FormattingEnterUrl" = "Enter URL..."; "PreviewWebPageClose" = "Clear Webpage Preview"; "MediaLocaltionImageAlt" = "Location on a map"; @@ -1395,6 +1414,12 @@ "ProfileOpenAppAbout" = "By launching this mini app, you agree to the {terms}."; "ProfileOpenAppTerms" = "Terms of Service for Mini Apps"; "ProfileBotOpenAppInfoLink" = "https://telegram.org/tos/mini-apps"; +"ProfileBirthday" = "Date of birth"; +"ProfileBirthdayToday" = "Birthday today"; +"ProfileBirthdayValue" = "{date}"; +"ProfileBirthdayValueYear" = "{date} ({age} years old)"; +"ProfileBirthdayTodayValue" = "🎂 {date}"; +"ProfileBirthdayTodayValueYear" = "🎂 {date} ({age} years old)"; "MonetizationInfoTONTitle" = "What is 💎 TON?"; "ChannelEarnLearnCoinAbout" = "TON is a blockchain platform and cryptocurrency that Telegram uses for its high speed and low commissions on transactions. {link}"; "MonetizationBalanceZeroInfo" = "You will be able to collect rewards using Fragment, a third-party platform used by advertisers to pay for ads. {link}"; @@ -1544,6 +1569,7 @@ "StarsReactionTerms" = "By sending Stars you agree to the {link}"; "StarsReactionLinkText" = "Terms of Service"; "StarsReactionLink" = "https://telegram.org/tos/stars"; +"AriaMiniApp" = "{bot} Mini App"; "MiniAppsMoreTabs_one" = "{botName} & {count} Other"; "MiniAppsMoreTabs_other" = "{botName} & {count} Others"; "PrizeCredits2_one" = "Your prize is {count} Star."; @@ -1645,6 +1671,9 @@ "SearchTabVoice" = "Voice"; "SearchTabMessages" = "Messages"; "SearchTabPublicPosts" = "Posts"; +"SearchResultTopics" = "Topics"; +"SearchResultMyChannels" = "Channels you joined"; +"SearchResultRecommendedChannels" = "Similar Channels"; "StarsTransactionsAll" = "All Transactions"; "StarsTransactionsIncoming" = "Incoming"; "StarsTransactionsOutgoing" = "Outgoing"; @@ -1701,6 +1730,8 @@ "CheckPasswordTitle" = "Enter Password"; "CheckPasswordPlaceholder" = "Password"; "CheckPasswordDescription" = "Please enter your password to continue."; +"PasswordFormPlaceholder" = "Password"; +"PasswordFormSubmit" = "Next"; "ActionFallbackUser" = "User"; "ActionFallbackChat" = "Chat"; "ActionFallbackChannel" = "Channel"; @@ -1921,8 +1952,8 @@ "GiftPremiumPayWithStarsAcc" = "Pay with stars"; "GetMoreStarsLinkText" = "Get More Stars >"; "GiftPremiumDescriptionYourBalance" = "Your balance is **{stars}**. {link}"; -"StarsGiftCompleted"= "Gift sent!"; -"GiftSent"= "Gift sent!"; +"StarsGiftCompleted" = "Gift sent!"; +"GiftSent" = "Gift sent!"; "PrivacyDescriptionMessagesContactsAndPremium" = "You can restrict messages from users who are not in your contacts and don't have Premium."; "PrivacyChargeForMessages" = "Charge for Messages"; "PrivacyDescriptionChargeForMessages" = "Charge a fee for messages from people outside your contacts or those you haven't messaged first."; @@ -1948,7 +1979,7 @@ "MessageSentPaidToastText" = "You paid {amount}"; "ButtonUndo" = "Undo"; "ActionPaidOneMessageOutgoing" = "You paid {amount} to send a message"; -"ActionPaidOneMessageIncoming" = "You received {amount} from {user}"; +"ActionPaidOneMessageIncoming" = "{user} paid {amount} to send a message"; "PaneMessagePaidMessageCharge" = "{peer} must pay {amount} for each message to you."; "ConfirmRemoveMessageFee" = "Yes"; "ConfirmDialogMessageRemoveFee" = "Are you sure you want to allow **{peer}** to message you for free?"; @@ -1967,7 +1998,7 @@ "ComposerSubtitleFrozenAccount" = "Tap to view details"; "DescriptionRestrictedMedia" = "Posting media content is not allowed in this group."; "DescriptionScheduledPaidMediaNotAllowed" = "Posting scheduled paid media content is not allowed"; -"DescriptionScheduledPaidMessagesNotAllowed" = "Scheduled paid messages is not allowed"; +"DescriptionScheduledPaidMessagesNotAllowed" = "Paid messages can't be scheduled"; "GroupMessagesChargePrice" = "Charge Stars for Messages"; "RightsChargeStarsAbout" = "If you turn this on, regular members of the group will have to pay Stars to send messages."; "SetPriceGroupDescription" = "Your group will receive {percent} of the selected fee (~{amount}) for each incoming messages."; @@ -1996,7 +2027,7 @@ "GiftRibbonSale" = "sale"; "ButtonBuyGift" = "Buy for {stars}"; "GiftInfoBuyGift" = "{user} is selling this gift and you can buy it."; -"StarsGiftBought"= "You bought gift!"; +"StarsGiftBought" = "You bought a gift!"; "ButtonSellGift" = "Sell for {stars}"; "GiftSellTitle" = "Sell Gift"; "Sell" = "Sell"; @@ -2035,7 +2066,7 @@ "SendInStandardQuality" = "Send In Standard Quality"; "SendInHighQuality" = "Send In High Quality"; "MonoforumBadge" = "DIRECT"; -"MonoforumStatus" = "Channel messages"; +"MonoforumStatus" = "Direct messages"; "MonoforumComposerPlaceholder" = "Choose a message to reply"; "ChannelSendMessage" = "Direct Messages"; "AutomaticTranslation" = "Automatic Translation"; @@ -2043,7 +2074,7 @@ "ComposerEmbeddedMessageSuggestedPostDescription" = "Tap to offer a price for publishing"; "TitleSuggestedPostAmountForAnyTime" = "{amount} for publishing anytime"; "ActionSuggestedPostOutgoing" = "**You** suggest to post this message."; -"ActionSuggestedPostIncoming" = "**{user}** suggest to post this message."; +"ActionSuggestedPostIncoming" = "**{user}** suggested to post this message."; "ActionSuggestedChangesPrice" = "price"; "ActionSuggestedChangesText" = "text"; "ActionSuggestedChangesTime" = "time"; @@ -2063,7 +2094,7 @@ "SuggestMessageTimeDescription" = "{hint} The post will remain available for at least {duration} from this date."; "SuggestMessageAnytime" = "Anytime"; "ButtonOfferAmount" = "Offer {amount}"; -"ButtonOfferFree" = "Offer Free"; +"ButtonOfferFree" = "Offer for Free"; "ButtonUpdateTerms" = "Update Terms"; "InputPlaceholderPrice" = "Enter Price"; "SuggestedPostApprove" = "Approve"; @@ -2079,10 +2110,10 @@ "SuggestedPostPublishedYou" = "📅 Your post was automatically published on {peer} **{date}**."; "SuggestedPostCharged" = "💰 {user} has been charged {amount}."; "SuggestedPostChargedYou" = "💰 You have been charged {amount}."; -"SuggestedPostReceiveAmount" = "⏳ {peer} will receive the {currency} once the post has been live for {duration}."; -"SuggestedPostReceiveAmountYou" = "⏳ {peer} will receive your {currency} once the post has been live for {duration}."; +"SuggestedPostReceiveAmount" = "⏳ {peer} will receive the payment once the post has been live for {duration}."; +"SuggestedPostReceiveAmountYou" = "⏳ {peer} will receive your payment once the post has been live for {duration}."; "SuggestedPostRefund" = "🔄 If {peer} removes the post before it has been live for {duration}, payment will be refunded."; -"SuggestedPostRefundYou" = "🔄 If {peer} removes the post before it has been live for {duration}, your {currency} will be refunded."; +"SuggestedPostRefundYou" = "🔄 If {peer} removes the post before it has been live for {duration}, your payment will be refunded."; "SuggestedPostBalanceTooLow" = "⚠️ **Transaction failed** because {peer} didn't have enough {currency}."; "SuggestedPostRefundedByUser" = "{channel} will not receive {amount} because {user} requested a refund."; "SuggestedPostRefundedByChannel" = "{amount} was returned to {peer} because {channel} deleted the message."; @@ -2092,8 +2123,8 @@ "DeclinePostDialogQuestion" = "Do you want to decline this post from **{sender}**?"; "SuggestedPostRejected" = "**{peer}** rejected this message."; "SuggestedPostRejectedYou" = "You rejected this message."; -"SuggestedPostRejectedWithReason" = "**{peer}** rejected this message with the comment."; -"SuggestedPostRejectedWithReasonYou" = "You rejected this message with the comment."; +"SuggestedPostRejectedWithReason" = "**{peer}** rejected this message with the comment:"; +"SuggestedPostRejectedWithReasonYou" = "You rejected this message with the comment:"; "SuggestedPostRejectedComment" = "\"{comment}\""; "ActionSuggestedPostSuccess" = "{channel} has received {amount} for publishing post"; "ComposerPlaceholderCaption" = "Caption"; @@ -2101,15 +2132,15 @@ "SuggestedPostConfirmTitle" = "Accept Terms"; "SuggestedPostConfirmMessage" = "Do you want to publish this post from **{peer}**?"; "SuggestedPostConfirmDetailsAdmin" = "You will receive **{amount}** ({commission}%) for publishing this post. It must remain visible for at least {duration} after publication."; -"SuggestedPostConfirmDetailsUser" = "You will pay **{amount}** ({commission}%) for publishing this post. It must remain visible for at least {duration} after publication."; +"SuggestedPostConfirmDetailsUser" = "You will pay **{amount}** for publishing this post. It must remain visible for at least {duration} after publication."; "SuggestedPostConfirmDetailsWithTimeAdmin" = "You will receive **{amount}** ({commission}%) for publishing this post **{time}**. It must remain visible for at least {duration} after publication."; -"SuggestedPostConfirmDetailsWithTimeUser" = "You will pay **{amount}** ({commission}%) for publishing this post **{time}**. It must remain visible for at least {duration} after publication."; +"SuggestedPostConfirmDetailsWithTimeUser" = "You will pay **{amount}** for publishing this post **{time}**. It must remain visible for at least {duration} after publication."; "ButtonPublish" = "Publish"; -"ButtonPublishAtTime" = "Publish {time}"; +"ButtonPublishAtTime" = "Post {time}"; "PublishNow" = "Publish Now"; "TitleNewToDoList" = "New Checklist"; "TitleEditToDoList" = "Edit Checklist"; -"TitleAppendToDoList" = "Append Checklist"; +"TitleAppendToDoList" = "Add Task"; "InputTitle" = "Title"; "TitleToDoList" = "Checklist"; "TitleTask" = "Task"; @@ -2139,16 +2170,17 @@ "PremiumMore" = "More"; "SubscribeToTelegramPremiumForToggleTask" = "Subscribe to **Telegram Premium** to toggle tasks"; "SubscribeToTelegramPremiumForCreateToDo" = "Subscribe to **Telegram Premium** to create Checklists"; -"SubscribeToTelegramPremiumForAppendToDo" = "Subscribe to **Telegram Premium** to append Checklists"; -"HintTodoListTasksCount" = "You can add {count} more tasks"; +"SubscribeToTelegramPremiumForAppendToDo" = "Subscribe to **Telegram Premium** to add tasks"; +"HintTodoListTasksCount2_one" = "You can add {count} more task"; +"HintTodoListTasksCount2_other" = "You can add {count} more tasks"; "ToDoListErrorChooseTitle" = "Please enter a title."; "ToDoListErrorChooseTasks" = "Please enter at least one task."; "GiftInfoCollectibleBy" = "Collectible #{number} by **{owner}**"; "PremiumPreviewTodo" = "Checklists"; "DescriptionAboutTon" = "Offer TON to submit post suggestions to channels on Telegram."; -"ButtonTopUpViaFragment" = "Top-Up Via Fragment"; -"TonModalHint" = "You can top-up your TON using Fragment."; -"TonGiftReceived" = "TON Top-Up"; +"ButtonTopUpViaFragment" = "Top Up Via Fragment"; +"TonModalHint" = "You can top up your TON using Fragment."; +"TonGiftReceived" = "TON Top Up"; "MediaSpoilerSensitive" = "18+"; "TitleSensitiveModal" = "{years}+ content"; "TextSensitiveModal" = "This media may contain sensitive content suitable only for adults. Do you still want to view it?"; @@ -2162,9 +2194,11 @@ "TitleAgeCheckSuccess" = "Age Check Success"; "ButtonAgeVerification" = "Verify My Age"; "GiftRibbonPremium" = "premium"; -"NotificationGiftsLimit" = "You've already sent {count} of these gifts, and it's the limit."; +"NotificationGiftsLimit2_one" = "You've already sent **one** of these gifts, and it's the limit."; +"NotificationGiftsLimit2_other" = "You've already sent {count} of these gifts, and it's the limit."; "PremiumGiftHeader" = "Premium Gift"; -"DescriptionGiftPremiumRequired" = "Subscribe to **Telegram Premium** to send up to **{count}** of these gifts and unlock access to multiple additional features."; +"DescriptionGiftPremiumRequired2_one" = "Subscribe to **Telegram Premium** to send **one** of these gifts and unlock powerful features."; +"DescriptionGiftPremiumRequired2_other" = "Subscribe to **Telegram Premium** to send up to **{count}** of these gifts and unlock powerful features."; "PriceInStars" = "Price in Stars"; "PriceInTON" = "Price in TON"; "DescriptionComposerGiftMinimumCurrencyPrice" = "Minimum price is **{amount}**."; @@ -2199,7 +2233,7 @@ "PublicPostsPremiumFeatureSubtitle" = "Global search is a Premium feature."; "PublicPostsSubscribeToPremium" = "Subscribe to Premium"; "NotificationPaidExtraSearch" = "{stars} spent on extra search."; -"PostsSearchTransaction" = "Posts Search"; +"PostsSearchTransaction" = "Public Post Search"; "TitleRating" = "Rating"; "RatingReflectsActivity" = "This rating reflects {name}'s activity on Telegram. It is based on:"; "RatingYourReflectsActivity" = "This rating reflects your activity on Telegram. It is based on:"; @@ -2218,4 +2252,7 @@ "DescriptionFutureRating_one" = "This will be your rating in {time}, after {points} point is added. {link}"; "DescriptionFutureRating_other" = "This will be your rating in {time}, after {points} points are added. {link}"; "LinkDescriptionRatingBack" = "Back >"; -"LinkDescriptionRatingPreview" = "Preview >"; \ No newline at end of file +"LinkDescriptionRatingPreview" = "Preview >"; +"ErrorFocusInaccessibleMessage" = "Unfortunately, you can't access this message. You aren't a member of the chat where it was posted."; +"ContextMenuHintMouse" = "To edit or reply, close this menu. Then right click on a message."; +"ContextMenuHintTouch" = "To edit or reply, close this menu. Then long tap on a message."; diff --git a/src/components/auth/AuthPassword.tsx b/src/components/auth/AuthPassword.tsx index ea13aef4d..62e265405 100644 --- a/src/components/auth/AuthPassword.tsx +++ b/src/components/auth/AuthPassword.tsx @@ -36,7 +36,7 @@ const AuthPassword: FC = ({

{lang('LoginHeaderPassword')}

{lang('LoginEnterPasswordDescription')}

{CONTENT_NOT_SUPPORTED}; + return {lang('MessageUnsupported')}; } return ( diff --git a/src/components/common/PasswordForm.tsx b/src/components/common/PasswordForm.tsx index c6b88a5df..e0edfed34 100644 --- a/src/components/common/PasswordForm.tsx +++ b/src/components/common/PasswordForm.tsx @@ -13,7 +13,7 @@ import stopEvent from '../../util/stopEvent'; import useTimeout from '../../hooks/schedulers/useTimeout'; import useAppLayout from '../../hooks/useAppLayout'; -import useOldLang from '../../hooks/useOldLang'; +import useLang from '../../hooks/useLang'; import Button from '../ui/Button'; import Icon from './icons/Icon'; @@ -29,8 +29,8 @@ type OwnProps = { shouldShowSubmit?: boolean; shouldResetValue?: boolean; isPasswordVisible?: boolean; - clearError: NoneToVoidFunction; noRipple?: boolean; + onClearError: NoneToVoidFunction; onChangePasswordVisibility: (state: boolean) => void; onInputChange?: (password: string) => void; onSubmit?: (password: string) => void; @@ -41,20 +41,21 @@ const PasswordForm: FC = ({ isPasswordVisible, error, hint, - placeholder = 'Password', - submitLabel = 'Next', + placeholder, + submitLabel, description, shouldShowSubmit, shouldResetValue, shouldDisablePasswordManager = false, noRipple = false, - clearError, + onClearError, onChangePasswordVisibility, onInputChange, onSubmit, }) => { const inputRef = useRef(); - const lang = useOldLang(); + + const lang = useLang(); const { isMobile } = useAppLayout(); const [password, setPassword] = useState(''); @@ -84,7 +85,7 @@ const PasswordForm: FC = ({ function onPasswordChange(e: ChangeEvent) { if (error) { - clearError(); + onClearError(); } const { target } = e; @@ -141,14 +142,14 @@ const PasswordForm: FC = ({ maxLength={256} dir="auto" /> - +
@@ -156,7 +157,7 @@ const PasswordForm: FC = ({ {description &&

{description}

} {onSubmit && (canSubmit || shouldShowSubmit) && ( )} diff --git a/src/components/common/VerificationMonetizationModal.tsx b/src/components/common/VerificationMonetizationModal.tsx index 7f604b22c..fe668b4f8 100644 --- a/src/components/common/VerificationMonetizationModal.tsx +++ b/src/components/common/VerificationMonetizationModal.tsx @@ -73,7 +73,7 @@ const VerificationMonetizationModal = ({ placeholder={lang('CheckPasswordPlaceholder')} error={renderingModal?.errorKey && lang.withRegular(renderingModal.errorKey)} description={lang('CheckPasswordDescription')} - clearError={handleClearError} + onClearError={handleClearError} isLoading={renderingModal?.isLoading} hint={passwordHint} isPasswordVisible={shouldShowPassword} diff --git a/src/components/common/WebLink.tsx b/src/components/common/WebLink.tsx index ba9b47c50..b6f89d51b 100644 --- a/src/components/common/WebLink.tsx +++ b/src/components/common/WebLink.tsx @@ -6,7 +6,8 @@ import type { ObserveFn } from '../../hooks/useIntersectionObserver'; import type { TextPart } from '../../types'; import { - getFirstLinkInMessage, getMessageText, + getFirstLinkInMessage, + getMessageTextWithFallback, } from '../../global/helpers'; import { selectWebPageFromMessage } from '../../global/selectors'; import buildClassName from '../../util/buildClassName'; @@ -15,6 +16,7 @@ import trimText from '../../util/trimText'; import { renderMessageSummary } from './helpers/renderMessageText'; import renderText from './helpers/renderText'; +import useLang from '../../hooks/useLang'; import useLastCallback from '../../hooks/useLastCallback'; import useOldLang from '../../hooks/useOldLang'; @@ -45,7 +47,8 @@ type StateProps = { const WebLink = ({ message, webPage, senderTitle, isProtected, observeIntersection, onMessageClick, }: OwnProps & StateProps) => { - const lang = useOldLang(); + const lang = useLang(); + const oldLang = useOldLang(); let linkData: ApiWebPageWithFormatted | undefined = webPage; @@ -57,7 +60,7 @@ const WebLink = ({ linkData = { siteName: domain.replace(/^www./, ''), url: url.includes('://') ? url : url.includes('@') ? `mailto:${url}` : `http://${url}`, - formattedDescription: getMessageText(message)?.text !== url + formattedDescription: getMessageTextWithFallback(lang, message)?.text !== url ? renderMessageSummary(lang, message, undefined, undefined, MAX_TEXT_LENGTH) : undefined, } as ApiWebPageWithFormatted; @@ -125,7 +128,7 @@ const WebLink = ({ onClick={handleMessageClick} isRtl={lang.isRtl} > - {formatPastTimeShort(lang, message.date * 1000)} + {formatPastTimeShort(oldLang, message.date * 1000)} )} diff --git a/src/components/common/embedded/EmbeddedMessage.tsx b/src/components/common/embedded/EmbeddedMessage.tsx index 530901893..86a60b93d 100644 --- a/src/components/common/embedded/EmbeddedMessage.tsx +++ b/src/components/common/embedded/EmbeddedMessage.tsx @@ -11,7 +11,7 @@ import type { ObserveFn } from '../../../hooks/useIntersectionObserver'; import type { ChatTranslatedMessages } from '../../../types'; import type { IconName } from '../../../types/icons'; -import { CONTENT_NOT_SUPPORTED, TON_CURRENCY_CODE } from '../../../config'; +import { TON_CURRENCY_CODE } from '../../../config'; import { getMessageIsSpoiler, getMessageRoundVideo, @@ -213,8 +213,8 @@ const EmbeddedMessage: FC = ({ function renderMediaContentType(media?: MediaContainer) { if (!media || media.content.text) return NBSP; - const description = getMediaContentTypeDescription(oldLang, media.content, {}); - if (!description || description === CONTENT_NOT_SUPPORTED) return NBSP; + const description = getMediaContentTypeDescription(lang, media.content, {}); + if (!description) return NBSP; return ( {renderText(description)} diff --git a/src/components/common/helpers/renderMessageText.ts b/src/components/common/helpers/renderMessageText.ts index d21247aee..4497f2ce8 100644 --- a/src/components/common/helpers/renderMessageText.ts +++ b/src/components/common/helpers/renderMessageText.ts @@ -1,13 +1,12 @@ import { getGlobal } from '../../../global'; import type { ApiMessage, ApiSponsoredMessage } from '../../../api/types'; -import type { OldLangFn } from '../../../hooks/useOldLang'; import type { TextPart, ThreadId } from '../../../types'; import { ApiMessageEntityTypes } from '../../../api/types'; import { getMessageStatefulContent, - getMessageText, + getMessageTextWithFallback, } from '../../../global/helpers'; import { getMessageSummaryDescription, @@ -16,6 +15,7 @@ import { TRUNCATED_SUMMARY_LENGTH, } from '../../../global/helpers/messageSummary'; import { getMessageKey } from '../../../util/keys/messageKey'; +import { getTranslationFn, type LangFn } from '../../../util/localization'; import trimText from '../../../util/trimText'; import renderText from './renderText'; import { renderTextWithEntities } from './renderTextWithEntities'; @@ -48,7 +48,7 @@ export function renderMessageText({ const { text, entities } = message.content.text || {}; if (!text) { - const contentNotSupportedText = getMessageText(message)?.text; + const contentNotSupportedText = getMessageTextWithFallback(getTranslationFn(), message)?.text; return contentNotSupportedText ? [trimText(contentNotSupportedText, truncateLength)] : undefined; } @@ -73,7 +73,7 @@ export function renderMessageText({ // TODO Use Message Summary component instead export function renderMessageSummary( - lang: OldLangFn, + lang: LangFn, message: ApiMessage, noEmoji = false, highlight?: string, diff --git a/src/components/common/profile/UserBirthday.tsx b/src/components/common/profile/UserBirthday.tsx index 962a87412..c3e6e5edd 100644 --- a/src/components/common/profile/UserBirthday.tsx +++ b/src/components/common/profile/UserBirthday.tsx @@ -19,8 +19,8 @@ import renderText from '../helpers/renderText'; import useTimeout from '../../../hooks/schedulers/useTimeout'; import useFlag from '../../../hooks/useFlag'; +import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; -import useOldLang from '../../../hooks/useOldLang'; import ListItem from '../../ui/ListItem'; import StickerView from '../StickerView'; @@ -58,7 +58,7 @@ const UserBirthday = ({ const animationPlayedRef = useRef(false); const [isPlayingAnimation, playAnimation, stopAnimation] = useFlag(); - const lang = useOldLang(); + const lang = useLang(); const { formattedDate, @@ -139,7 +139,17 @@ const UserBirthday = ({ } }, [isInSettings, isPlayingAnimation]); - const valueKey = `ProfileBirthday${isToday ? 'Today' : ''}Value${age ? 'Year' : ''}`; + const value = useMemo(() => { + if (age) { + return lang( + `ProfileBirthday${isToday ? 'Today' : ''}ValueYear`, + { date: formattedDate, age }, + { pluralValue: age }, + ); + } + + return lang(`ProfileBirthday${isToday ? 'Today' : ''}Value`, { date: formattedDate }); + }, [age, formattedDate, isToday, lang]); const canGiftPremium = isToday && !user.isPremium && !user.isSelf && !isPremiumPurchaseBlocked; @@ -175,7 +185,7 @@ const UserBirthday = ({ onSecondaryIconClick={handleOpenGiftModal} >
- {renderText(lang(valueKey, [formattedDate, age], undefined, age))} + {renderText(value)}
{lang(isToday ? 'ProfileBirthdayToday' : 'ProfileBirthday')} diff --git a/src/components/left/search/ChatMessage.tsx b/src/components/left/search/ChatMessage.tsx index 6409526a8..1542cdefd 100644 --- a/src/components/left/search/ChatMessage.tsx +++ b/src/components/left/search/ChatMessage.tsx @@ -6,7 +6,6 @@ import type { ApiChat, ApiMessage, ApiMessageOutgoingStatus, ApiUser, } from '../../../api/types'; -import type { OldLangFn } from '../../../hooks/useOldLang'; import { getMessageIsSpoiler, @@ -18,11 +17,13 @@ import { import { selectChat, selectUser } from '../../../global/selectors'; import buildClassName from '../../../util/buildClassName'; import { formatPastTimeShort } from '../../../util/dates/dateFormat'; +import { type LangFn } from '../../../util/localization'; import { renderMessageSummary } from '../../common/helpers/renderMessageText'; import useMessageMediaHash from '../../../hooks/media/useMessageMediaHash'; import useThumbnail from '../../../hooks/media/useThumbnail'; import useAppLayout from '../../../hooks/useAppLayout'; +import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import useMedia from '../../../hooks/useMedia'; import useOldLang from '../../../hooks/useOldLang'; @@ -68,7 +69,8 @@ const ChatMessage: FC = ({ focusMessage({ chatId, messageId: message.id, shouldReplaceHistory: true }); }); - const lang = useOldLang(); + const lang = useLang(); + const oldLang = useOldLang(); const buttonRef = useSelectWithEnter(handleClick); @@ -98,7 +100,7 @@ const ChatMessage: FC = ({ />
- {formatPastTimeShort(lang, message.date * 1000)} + {formatPastTimeShort(oldLang, message.date * 1000)}
@@ -114,7 +116,7 @@ const ChatMessage: FC = ({ }; function renderSummary( - lang: OldLangFn, message: ApiMessage, blobUrl?: string, searchQuery?: string, isRoundVideo?: boolean, + lang: LangFn, message: ApiMessage, blobUrl?: string, searchQuery?: string, isRoundVideo?: boolean, ) { if (!blobUrl) { return renderMessageSummary(lang, message, undefined, searchQuery); diff --git a/src/components/left/search/ChatMessageResults.tsx b/src/components/left/search/ChatMessageResults.tsx index f0f5d5e9c..6b0a9b218 100644 --- a/src/components/left/search/ChatMessageResults.tsx +++ b/src/components/left/search/ChatMessageResults.tsx @@ -12,7 +12,7 @@ import { throttle } from '../../../util/schedulers'; import { renderMessageSummary } from '../../common/helpers/renderMessageText'; import useAppLayout from '../../../hooks/useAppLayout'; -import useOldLang from '../../../hooks/useOldLang'; +import useLang from '../../../hooks/useLang'; import NothingFound from '../../common/NothingFound'; import InfiniteScroll from '../../ui/InfiniteScroll'; @@ -53,7 +53,7 @@ const ChatMessageResults: FC = ({ }) => { const { searchMessagesGlobal, openThread } = getActions(); - const lang = useOldLang(); + const lang = useLang(); const { isMobile } = useAppLayout(); const handleLoadMore = useCallback(({ direction }: { direction: LoadMoreDirection }) => { @@ -133,14 +133,14 @@ const ChatMessageResults: FC = ({ {nothingFound && ( )} {Boolean(foundTopicIds?.length) && (

- {lang('Topics')} + {lang('SearchResultTopics')}

{foundTopicIds.map((id) => { return ( diff --git a/src/components/left/search/ChatResults.tsx b/src/components/left/search/ChatResults.tsx index 33d90c36a..07c98f785 100644 --- a/src/components/left/search/ChatResults.tsx +++ b/src/components/left/search/ChatResults.tsx @@ -31,7 +31,6 @@ import useHorizontalScroll from '../../../hooks/useHorizontalScroll'; import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; -import useOldLang from '../../../hooks/useOldLang'; import Icon from '../../common/icons/Icon'; import NothingFound from '../../common/NothingFound'; @@ -102,7 +101,6 @@ const ChatResults: FC = ({ const containerRef = useRef(); const chatSelectionRef = useRef(); - const oldLang = useOldLang(); const lang = useLang(); const { isMobile } = useAppLayout(); @@ -318,7 +316,7 @@ const ChatResults: FC = ({ function renderFoundMessage(message: ApiMessage) { const chatsById = getGlobal().chats.byId; - const text = renderMessageSummary(oldLang, message); + const text = renderMessageSummary(lang, message); const chat = chatsById[message.chatId]; if (!text || !chat) { @@ -375,14 +373,14 @@ const ChatResults: FC = ({ {nothingFound && ( )} {Boolean(localResults.length) && !isChannelList && (
{localResults.map((id) => ( @@ -397,13 +395,13 @@ const ChatResults: FC = ({ )} {Boolean(localResults.length) && (
-

+

{localResults.length > LESS_LIST_ITEMS_AMOUNT && ( - {oldLang(shouldShowMoreLocal ? 'ChatList.Search.ShowLess' : 'ChatList.Search.ShowMore')} + {lang(shouldShowMoreLocal ? 'ChatListSearchShowLess' : 'ChatListSearchShowMore')} )} - {oldLang(isChannelList ? 'SearchMyChannels' : 'DialogList.SearchSectionDialogs')} + {lang(isChannelList ? 'SearchResultMyChannels' : 'DialogListSearchSectionDialogs')}

{localResults.map((id, index) => { if (!shouldShowMoreLocal && index >= LESS_LIST_ITEMS_AMOUNT) { @@ -422,13 +420,13 @@ const ChatResults: FC = ({ )} {Boolean(globalResults.length) && (
-

+

{globalResults.length > LESS_LIST_ITEMS_AMOUNT && ( - {oldLang(shouldShowMoreGlobal ? 'ChatList.Search.ShowLess' : 'ChatList.Search.ShowMore')} + {lang(shouldShowMoreGlobal ? 'ChatListSearchShowLess' : 'ChatListSearchShowMore')} )} - {oldLang('DialogList.SearchSectionGlobal')} + {lang('DialogListSearchSectionGlobal')}

{sponsoredPeer && ( @@ -450,8 +448,8 @@ const ChatResults: FC = ({ )} {Boolean(suggestedChannelIds?.length) && !searchQuery && (
-

- {oldLang('SearchRecommendedChannels')} +

+ {lang('SearchResultRecommendedChannels')}

{suggestedChannelIds.map((id) => { return ( @@ -468,7 +466,7 @@ const ChatResults: FC = ({ {renderContextMenu()} {shouldRenderMessagesSection && (
-

+

{!isChannelList && ( {lang('SearchContextCaption', { @@ -489,7 +487,7 @@ const ChatResults: FC = ({ )} - {oldLang('SearchMessages')} + {lang('SearchMessages')}

{actualFoundIds.map(renderFoundMessage)}
diff --git a/src/components/left/search/PublicPostsResults.tsx b/src/components/left/search/PublicPostsResults.tsx index d5891d3d3..9bf771f3c 100644 --- a/src/components/left/search/PublicPostsResults.tsx +++ b/src/components/left/search/PublicPostsResults.tsx @@ -16,7 +16,6 @@ import { renderMessageSummary } from '../../common/helpers/renderMessageText'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; -import useOldLang from '../../../hooks/useOldLang'; import NothingFound from '../../common/NothingFound'; import InfiniteScroll from '../../ui/InfiniteScroll'; @@ -53,7 +52,6 @@ const PublicPostsResults = ({ const { searchMessagesGlobal } = getActions(); const lang = useLang(); - const oldLang = useOldLang(); const handleSearch = useLastCallback(() => { if (!searchQuery) return; @@ -90,7 +88,7 @@ const PublicPostsResults = ({ function renderFoundMessage(message: ApiMessage) { const chatsById = getGlobal().chats.byId; - const text = renderMessageSummary(oldLang, message); + const text = renderMessageSummary(lang, message); const chat = chatsById[message.chatId]; if (!text || !chat) { @@ -130,8 +128,8 @@ const PublicPostsResults = ({ > {isNothingFound && ( )} diff --git a/src/components/left/settings/SettingsActiveSession.tsx b/src/components/left/settings/SettingsActiveSession.tsx index 1017c3267..b854fae00 100644 --- a/src/components/left/settings/SettingsActiveSession.tsx +++ b/src/components/left/settings/SettingsActiveSession.tsx @@ -9,7 +9,7 @@ import { formatDateTimeToString } from '../../../util/dates/dateFormat'; import getSessionIcon from './helpers/getSessionIcon'; import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev'; -import useOldLang from '../../../hooks/useOldLang'; +import useLang from '../../../hooks/useLang'; import Icon from '../../common/icons/Icon'; import Button from '../../ui/Button'; @@ -33,7 +33,7 @@ const SettingsActiveSession: FC = ({ isOpen, session, onClose, }) => { const { changeSessionSettings, terminateAuthorization } = getActions(); - const lang = useOldLang(); + const lang = useLang(); const renderingSession = useCurrentOrPrev(session, true); @@ -66,13 +66,13 @@ const SettingsActiveSession: FC = ({ -
{lang('SessionPreview.Title')}
+
{lang('SessionPreviewTitle')}
); @@ -91,12 +91,12 @@ const SettingsActiveSession: FC = ({ )} />

{renderingSession?.deviceModel}

-
+
{formatDateTimeToString(renderingSession.dateActive * 1000, lang.code)}
-
{lang('SessionPreview.App')}
+
{lang('SessionPreviewApp')}
{renderingSession?.appName} {' '} @@ -107,20 +107,23 @@ const SettingsActiveSession: FC = ({ {' '} {renderingSession?.systemVersion}
+ {renderingSession?.ip && ( + <> +
{lang('SessionPreviewIp')}
+
{renderingSession.ip}
+ + )} -
{lang('SessionPreview.Ip')}
-
{renderingSession?.ip}
- -
{lang('SessionPreview.Location')}
+
{lang('SessionPreviewLocation')}
{renderingSession && getLocation(renderingSession)}
-

{lang('SessionPreview.IpDesc')}

+

{lang('SessionPreviewIpDesc')}

-

{lang('AuthSessions.View.AcceptTitle')}

+

{lang('AuthSessionsViewAcceptTitle')}

- {lang('SessionPreview.Accept.Secret')} + {lang('SessionPreviewAcceptSecret')} = ({ /> - {lang('SessionPreview.Accept.Calls')} + {lang('SessionPreviewAcceptCalls')} = ({ changeSessionTtl, } = getActions(); - const lang = useOldLang(); + const oldLang = useOldLang(); + const lang = useLang(); const [isConfirmTerminateAllDialogOpen, openConfirmTerminateAllDialog, closeConfirmTerminateAllDialog] = useFlag(); const [openedSessionHash, setOpenedSessionHash] = useState(); const [isModalOpen, openModal, closeModal] = useFlag(); @@ -80,21 +82,21 @@ const SettingsActiveSessions: FC = ({ const AUTO_TERMINATE_OPTIONS = useMemo(() => { const options = [{ - label: lang('Weeks', 1, 'i'), + label: lang('Weeks', { count: 1 }, { pluralValue: 1 }), value: '7', }, { - label: lang('Months', 1, 'i'), + label: lang('Months', { count: 1 }, { pluralValue: 1 }), value: '30', }, { - label: lang('Months', 3, 'i'), + label: lang('Months', { count: 3 }, { pluralValue: 3 }), value: '90', }, { - label: lang('Months', 6, 'i'), + label: lang('Months', { count: 6 }, { pluralValue: 6 }), value: '183', }]; if (ttlDays && ttlDays >= 365) { options.push({ - label: lang('Years', 1, 'i'), + label: lang('Years', { count: 1 }, { pluralValue: 1 }), value: '365', }); } @@ -144,7 +146,7 @@ const SettingsActiveSessions: FC = ({ return (

- {lang('AuthSessions.CurrentSession')} + {lang('AuthSessionsCurrentSession')}

@@ -224,7 +226,7 @@ const SettingsActiveSessions: FC = ({ ripple narrow contextActions={[{ - title: 'Terminate', + title: lang('SessionTerminate'), icon: 'stop', destructive: true, handler: () => { @@ -236,7 +238,7 @@ const SettingsActiveSessions: FC = ({ onClick={() => { handleOpenSessionModal(session.hash); }} >
- {formatPastTimeShort(lang, session.dateActive * 1000)} + {formatPastTimeShort(oldLang, session.dateActive * 1000)} {session.deviceModel} {session.appName} diff --git a/src/components/left/settings/SettingsPasswordForm.tsx b/src/components/left/settings/SettingsPasswordForm.tsx index b71def335..487ed95b2 100644 --- a/src/components/left/settings/SettingsPasswordForm.tsx +++ b/src/components/left/settings/SettingsPasswordForm.tsx @@ -2,7 +2,7 @@ import type { FC } from '../../../lib/teact/teact'; import { memo, useCallback, useState } from '../../../lib/teact/teact'; import useHistoryBack from '../../../hooks/useHistoryBack'; -import useOldLang from '../../../hooks/useOldLang'; +import useLang from '../../../hooks/useLang'; import PasswordForm from '../../common/PasswordForm'; import PasswordMonkey from '../../common/PasswordMonkey'; @@ -15,46 +15,44 @@ type OwnProps = { placeholder?: string; hint?: string; submitLabel?: string; - clearError?: NoneToVoidFunction; - onSubmit: (password: string) => void; isActive?: boolean; + onSubmit: (password: string) => void; + onClearError?: NoneToVoidFunction; onReset: () => void; }; -const EQUAL_PASSWORD_ERROR = 'Passwords Should Be Equal'; - const SettingsPasswordForm: FC = ({ isActive, - onReset, error, isLoading, shouldDisablePasswordManager, expectedPassword, - placeholder = 'Current Password', + placeholder, hint, submitLabel, - clearError, onSubmit, + onClearError, + onReset, }) => { const [validationError, setValidationError] = useState(''); const [shouldShowPassword, setShouldShowPassword] = useState(false); + const lang = useLang(); + const handleSubmit = useCallback((newPassword) => { if (expectedPassword && newPassword !== expectedPassword) { - setValidationError(EQUAL_PASSWORD_ERROR); + setValidationError(lang('SettingsPasswordEqual')); } else { onSubmit(newPassword); } - }, [onSubmit, expectedPassword]); + }, [onSubmit, expectedPassword, lang]); const handleClearError = useCallback(() => { - if (clearError) { - clearError(); + if (onClearError) { + onClearError(); } setValidationError(''); - }, [clearError]); - - const lang = useOldLang(); + }, [onClearError]); useHistoryBack({ isActive, @@ -71,10 +69,10 @@ const SettingsPasswordForm: FC = ({
-

Resource-Intensive Processes

+

{lang('SettingsPerformanceGranularTitle')}

{PERFORMANCE_OPTIONS.map(([sectionName, options], index) => { return ( diff --git a/src/components/left/settings/folders/SettingsFoldersMain.tsx b/src/components/left/settings/folders/SettingsFoldersMain.tsx index 15506cecc..11759fd5a 100644 --- a/src/components/left/settings/folders/SettingsFoldersMain.tsx +++ b/src/components/left/settings/folders/SettingsFoldersMain.tsx @@ -20,7 +20,7 @@ import { renderTextWithEntities } from '../../../common/helpers/renderTextWithEn import { useFolderManagerForChatsCount } from '../../../../hooks/useFolderManager'; import useHistoryBack from '../../../../hooks/useHistoryBack'; -import useOldLang from '../../../../hooks/useOldLang'; +import useLang from '../../../../hooks/useLang'; import usePreviousDeprecated from '../../../../hooks/usePreviousDeprecated'; import AnimatedIconWithPreview from '../../../common/AnimatedIconWithPreview'; @@ -117,7 +117,7 @@ const SettingsFoldersMain: FC = ({ onCreateFolder(); }, [foldersById, maxFolders, onCreateFolder, openLimitReachedModal]); - const lang = useOldLang(); + const lang = useLang(); useHistoryBack({ isActive, @@ -226,7 +226,7 @@ const SettingsFoldersMain: FC = ({ {canCreateNewFolder && (
diff --git a/src/components/left/settings/passcode/SettingsPasscode.tsx b/src/components/left/settings/passcode/SettingsPasscode.tsx index 026813f16..b4c0c6532 100644 --- a/src/components/left/settings/passcode/SettingsPasscode.tsx +++ b/src/components/left/settings/passcode/SettingsPasscode.tsx @@ -160,7 +160,7 @@ const SettingsPasscode: FC = ({ = ({ void; }; const SettingsPasscodeStart: FC = ({ isActive, onReset, onStart, }) => { - const lang = useOldLang(); + const lang = useLang(); useHistoryBack({ isActive, onBack: onReset }); @@ -36,11 +36,10 @@ const SettingsPasscodeStart: FC = ({ />

- When you set up an additional passcode, a lock icon will appear on the chats page. - Tap it to lock and unlock your Telegram Web A. + {lang('SettingsPasscodeStart1', undefined, { withNodes: true, renderTextFilters: ['br'] })}

- Note: if you forget your local passcode, you'll need to log out of Telegram Web A and log in again. + {lang('SettingsPasscodeStart2', undefined, { withNodes: true, renderTextFilters: ['br'] })}

diff --git a/src/components/left/settings/twoFa/SettingsTwoFa.tsx b/src/components/left/settings/twoFa/SettingsTwoFa.tsx index 65e71a609..2b38d3e12 100644 --- a/src/components/left/settings/twoFa/SettingsTwoFa.tsx +++ b/src/components/left/settings/twoFa/SettingsTwoFa.tsx @@ -284,7 +284,7 @@ const SettingsTwoFa: FC = ({ = ({ = ({ = ({ error={validationError} placeholder={lang('Passcode.EnterPasscodePlaceholder')} submitLabel={lang('Next')} - clearError={handleClearError} + onClearError={handleClearError} isPasswordVisible={shouldShowPasscode} noRipple onChangePasswordVisibility={setShouldShowPasscode} diff --git a/src/components/main/PermissionCheckboxList.tsx b/src/components/main/PermissionCheckboxList.tsx index 614a51e86..fe5297bfd 100644 --- a/src/components/main/PermissionCheckboxList.tsx +++ b/src/components/main/PermissionCheckboxList.tsx @@ -12,8 +12,8 @@ import { selectChat, selectChatFullInfo } from '../../global/selectors'; import buildClassName from '../../util/buildClassName'; import stopEvent from '../../util/stopEvent'; +import useLang from '../../hooks/useLang'; import useLastCallback from '../../hooks/useLastCallback'; -import useOldLang from '../../hooks/useOldLang'; import Checkbox from '../ui/Checkbox'; @@ -61,7 +61,7 @@ const PermissionCheckboxList: FC = ({ const { isForum } = chat || {}; - const lang = useOldLang(); + const lang = useLang(); const isPublic = useMemo(() => chat && isChatPublic(chat), [chat]); const shouldDisablePermissionForPublicGroup = hasLinkedChat || isPublic; @@ -81,7 +81,7 @@ const PermissionCheckboxList: FC = ({ }); const handleDisabledClick = useLastCallback(() => { - showNotification({ message: lang('lng_rights_permission_unavailable') }); + showNotification({ message: lang('ChatPermissionNotAvailable') }); }); return ( @@ -119,7 +119,7 @@ const PermissionCheckboxList: FC = ({ = ({ = ({ = ({ = ({ = ({ = ({ = ({ = ({ = ({ = ({ } function getHeaderDescription() { - if (gift) { - const perUserTotal = gift.type !== 'starGiftUnique' ? gift.perUserTotal : 0; - return lang('DescriptionGiftPremiumRequired', { count: perUserTotal }); + if (gift && gift.type !== 'starGiftUnique' && gift.perUserTotal) { + return lang('DescriptionGiftPremiumRequired2', { count: gift.perUserTotal }, { + pluralValue: gift.perUserTotal, + }); } if (isGift) { diff --git a/src/components/middle/composer/DropTarget.tsx b/src/components/middle/composer/DropTarget.tsx index f5cf579fa..34298f7f3 100644 --- a/src/components/middle/composer/DropTarget.tsx +++ b/src/components/middle/composer/DropTarget.tsx @@ -6,6 +6,7 @@ import buildClassName from '../../../util/buildClassName'; import useEffectOnce from '../../../hooks/useEffectOnce'; import useFlag from '../../../hooks/useFlag'; +import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import useResizeObserver from '../../../hooks/useResizeObserver'; @@ -23,6 +24,8 @@ const DropTarget: FC = ({ isQuick, isGeneric, onFileSelect }) => { const ref = useRef(); const svgRef = useRef(); + const lang = useLang(); + const [isHovered, markHovered, unmarkHovered] = useFlag(); const handleDragLeave = useLastCallback((e: React.DragEvent) => { @@ -65,13 +68,17 @@ const DropTarget: FC = ({ isQuick, isGeneric, onFileSelect }) => { onDragLeave={handleDragLeave} data-dropzone > - +
-
Drop files here to send them
- {!isGeneric &&
{isQuick ? 'in a quick way' : 'without compression'}
} +
{lang('FileDropZoneTitle')}
+ {!isGeneric && ( +
+ {isQuick ? lang('FileDropZoneQuick') : lang('FileDropZoneNoCompression')} +
+ )}
); diff --git a/src/components/middle/composer/TextFormatter.tsx b/src/components/middle/composer/TextFormatter.tsx index f7039f68d..46af267a8 100644 --- a/src/components/middle/composer/TextFormatter.tsx +++ b/src/components/middle/composer/TextFormatter.tsx @@ -16,8 +16,8 @@ import stopEvent from '../../../util/stopEvent'; import { INPUT_CUSTOM_EMOJI_SELECTOR } from './helpers/customEmoji'; import useFlag from '../../../hooks/useFlag'; +import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; -import useOldLang from '../../../hooks/useOldLang'; import useShowTransitionDeprecated from '../../../hooks/useShowTransitionDeprecated'; import useVirtualBackdrop from '../../../hooks/useVirtualBackdrop'; @@ -71,6 +71,8 @@ const TextFormatter: FC = ({ const [inputClassName, setInputClassName] = useState(); const [selectedTextFormats, setSelectedTextFormats] = useState({}); + const lang = useLang(); + useEffect(() => (isOpen ? captureEscKeyListener(onClose) : undefined), [isOpen, onClose]); useVirtualBackdrop( isOpen, @@ -338,7 +340,7 @@ const TextFormatter: FC = ({ document.execCommand( 'insertHTML', false, - `${text}`, + `${text}`, ); onClose(); }); @@ -377,10 +379,9 @@ const TextFormatter: FC = ({ return () => document.removeEventListener('keydown', handleKeyDown); }, [isOpen, handleKeyDown]); - const lang = useOldLang(); - function handleContainerKeyDown(e: React.KeyboardEvent) { if (e.key === 'Enter' && isLinkControlOpen) { + if (!linkUrl.trim()) return; handleLinkUrlConfirm(); e.preventDefault(); } @@ -417,7 +418,7 @@ const TextFormatter: FC = ({
-
@@ -485,7 +486,7 @@ const TextFormatter: FC = ({ className="TextFormatter-link-url-input" type="text" value={linkUrl} - placeholder="Enter URL..." + placeholder={lang('FormattingEnterUrl')} autoComplete="off" inputMode="url" dir="auto" diff --git a/src/components/middle/composer/ToDoListModal.tsx b/src/components/middle/composer/ToDoListModal.tsx index 0455575c9..f6c37463d 100644 --- a/src/components/middle/composer/ToDoListModal.tsx +++ b/src/components/middle/composer/ToDoListModal.tsx @@ -340,6 +340,8 @@ const ToDoListModal = ({ }); } + const moreTasksCount = maxItemsCount - items.length - (isAddTaskMode && editingTodo ? editingTodo.items.length : 0); + return ( {!isAddTaskMode && ( @@ -369,8 +371,10 @@ const ToDoListModal = ({
- {lang('HintTodoListTasksCount', { - count: maxItemsCount - items.length - (isAddTaskMode && editingTodo ? editingTodo.items.length : 0), + {lang('HintTodoListTasksCount2', { + count: moreTasksCount, + }, { + pluralValue: moreTasksCount, })}
diff --git a/src/components/middle/message/ActionMessageText.tsx b/src/components/middle/message/ActionMessageText.tsx index 9f15e5b50..6e1b1e53b 100644 --- a/src/components/middle/message/ActionMessageText.tsx +++ b/src/components/middle/message/ActionMessageText.tsx @@ -12,7 +12,7 @@ import { } from '../../../config'; import { getMainUsername, - getMessageInvoice, getMessageText, isChatChannel, + getMessageInvoice, getMessageTextWithFallback, isChatChannel, } from '../../../global/helpers'; import { getMessageContent } from '../../../global/helpers'; import { getPeerTitle } from '../../../global/helpers/peers'; @@ -116,7 +116,7 @@ const ActionMessageText = ({ switch (action.type) { case 'pinMessage': { if (replyMessage) { - const formattedText = getMessageText(replyMessage); + const formattedText = getMessageTextWithFallback(lang, replyMessage); if (formattedText) { const textLink = renderMessageLink( replyMessage, diff --git a/src/components/middle/message/Message.tsx b/src/components/middle/message/Message.tsx index 2b8a130d6..a790eccec 100644 --- a/src/components/middle/message/Message.tsx +++ b/src/components/middle/message/Message.tsx @@ -1763,7 +1763,7 @@ const Message: FC = ({ color="translucent-white" round size="tiny" - ariaLabel="Focus message" + ariaLabel={lang('FocusMessage')} onClick={isPinnedList ? handleFocus : handleFocusForwarded} > diff --git a/src/components/middle/message/actions/SuggestedPostApproval.tsx b/src/components/middle/message/actions/SuggestedPostApproval.tsx index 9d3ffbbea..dac5f191b 100644 --- a/src/components/middle/message/actions/SuggestedPostApproval.tsx +++ b/src/components/middle/message/actions/SuggestedPostApproval.tsx @@ -113,7 +113,6 @@ const SuggestedPostApproval = ({ {translateWithYou(lang, 'SuggestedPostReceiveAmount', !isAdmin, { peer: renderChatLink(), duration, - currency: currency === TON_CURRENCY_CODE ? lang('CurrencyTon') : lang('CurrencyStars'), }, { withMarkdown: true })}
@@ -121,7 +120,6 @@ const SuggestedPostApproval = ({ {translateWithYou(lang, 'SuggestedPostRefund', !isAdmin, { peer: renderChatLink(), duration, - currency: currency === TON_CURRENCY_CODE ? lang('CurrencyTon') : lang('CurrencyStars'), }, { withMarkdown: true })}
diff --git a/src/components/middle/message/helpers/copyOptions.ts b/src/components/middle/message/helpers/copyOptions.ts index f53ae6713..c3b107da7 100644 --- a/src/components/middle/message/helpers/copyOptions.ts +++ b/src/components/middle/message/helpers/copyOptions.ts @@ -21,6 +21,7 @@ import { copyTextToClipboard, } from '../../../../util/clipboard'; import getMessageIdsForSelectedText from '../../../../util/getMessageIdsForSelectedText'; +import { getTranslationFn } from '../../../../util/localization'; import * as mediaLoader from '../../../../util/mediaLoader'; import { renderMessageText } from '../../../common/helpers/renderMessageText'; @@ -99,7 +100,7 @@ export function getMessageCopyOptions( if (clipboardText) { copyHtmlToClipboard( clipboardText.join(''), - getMessageTextWithSpoilers(message, statefulContent)!, + getMessageTextWithSpoilers(getTranslationFn(), message, statefulContent)!, ); } } diff --git a/src/components/modals/gift/GiftItemStar.tsx b/src/components/modals/gift/GiftItemStar.tsx index 8838c7dda..0ad34f62b 100644 --- a/src/components/modals/gift/GiftItemStar.tsx +++ b/src/components/modals/gift/GiftItemStar.tsx @@ -86,9 +86,10 @@ function GiftItemStar({ if (isUserLimitReached) { showNotification({ - message: lang('NotificationGiftsLimit', { + message: lang('NotificationGiftsLimit2', { count: perUserTotal, }, { + pluralValue: perUserTotal!, withMarkdown: true, withNodes: true, }), diff --git a/src/components/modals/gift/withdraw/GiftWithdrawModal.tsx b/src/components/modals/gift/withdraw/GiftWithdrawModal.tsx index 36f390406..429ac7df5 100644 --- a/src/components/modals/gift/withdraw/GiftWithdrawModal.tsx +++ b/src/components/modals/gift/withdraw/GiftWithdrawModal.tsx @@ -142,7 +142,7 @@ const GiftWithdrawModal = ({ modal, hasPassword, passwordHint }: OwnProps & Stat placeholder={lang('CheckPasswordPlaceholder')} error={renderingModal?.errorKey && lang.withRegular(renderingModal?.errorKey)} description={lang('CheckPasswordDescription')} - clearError={clearGiftWithdrawError} + onClearError={clearGiftWithdrawError} isLoading={renderingModal?.isLoading} hint={passwordHint} isPasswordVisible={shouldShowPassword} diff --git a/src/components/modals/webApp/WebAppModalTabContent.tsx b/src/components/modals/webApp/WebAppModalTabContent.tsx index 79bcb5472..369176154 100644 --- a/src/components/modals/webApp/WebAppModalTabContent.tsx +++ b/src/components/modals/webApp/WebAppModalTabContent.tsx @@ -1056,7 +1056,7 @@ const WebAppModalTabContent: FC = ({ )} style={frameStyle} src={url} - title={`${bot?.firstName} Web App`} + title={lang('AriaMiniApp', { bot: bot?.firstName })} sandbox={SANDBOX_ATTRIBUTES} allow="camera; microphone; geolocation; clipboard-write;" allowFullScreen diff --git a/src/components/payment/PasswordConfirm.tsx b/src/components/payment/PasswordConfirm.tsx index 19414a494..804646db1 100644 --- a/src/components/payment/PasswordConfirm.tsx +++ b/src/components/payment/PasswordConfirm.tsx @@ -56,7 +56,7 @@ const PasswordConfirm: FC = ({ hint={passwordHint} description={oldLang('PaymentConfirmationMessage', cardName)} placeholder={oldLang('Password')} - clearError={clearPaymentError} + onClearError={clearPaymentError} shouldShowSubmit={false} shouldResetValue={isActive} isPasswordVisible={shouldShowPassword} diff --git a/src/components/payment/PaymentModal.tsx b/src/components/payment/PaymentModal.tsx index 0f2a60e9d..8f20c23d8 100644 --- a/src/components/payment/PaymentModal.tsx +++ b/src/components/payment/PaymentModal.tsx @@ -256,7 +256,7 @@ const PaymentModal: FC = ({ isText onClick={handleClearPaymentError} > - {oldLang('OK')} + {lang('OK')}
@@ -540,10 +540,7 @@ const PaymentModal: FC = ({ onCloseAnimationEnd={handleModalClose} >

- Sorry, Telegram Web A doesn't support payments with this provider yet. - {' '} -
- Please use one of our mobile apps to do this. + {lang('PaymentsProvidesNotSupported', undefined, { withNodes: true, renderTextFilters: ['br'] })}

diff --git a/src/components/right/Profile.tsx b/src/components/right/Profile.tsx index c292ef17b..d4af3da68 100644 --- a/src/components/right/Profile.tsx +++ b/src/components/right/Profile.tsx @@ -601,7 +601,7 @@ const Profile: FC = ({ className="content empty-list" > {!noSpinner && !forceRenderHiddenMembers && } - {forceRenderHiddenMembers && } + {forceRenderHiddenMembers && }
); } @@ -617,7 +617,7 @@ const Profile: FC = ({ switch (resultType) { case 'members': - text = areMembersHidden ? 'You have no access to group members list.' : 'No members found'; + text = areMembersHidden ? lang('ChatMemberListNoAccess') : lang('NoMembersFound'); break; case 'commonChats': text = oldLang('NoGroupsInCommon'); diff --git a/src/components/right/statistics/StatisticsRecentMessage.tsx b/src/components/right/statistics/StatisticsRecentMessage.tsx index f8a46f551..86146828b 100644 --- a/src/components/right/statistics/StatisticsRecentMessage.tsx +++ b/src/components/right/statistics/StatisticsRecentMessage.tsx @@ -3,7 +3,6 @@ import { memo, useCallback } from '../../../lib/teact/teact'; import { getActions } from '../../../global'; import type { ApiMessage, StatisticsMessageInteractionCounter } from '../../../api/types'; -import type { OldLangFn } from '../../../hooks/useOldLang'; import { getMessageRoundVideo, @@ -11,12 +10,13 @@ import { } from '../../../global/helpers'; import buildClassName from '../../../util/buildClassName'; import { formatDateTimeToString } from '../../../util/dates/dateFormat'; +import { type LangFn } from '../../../util/localization'; import { renderMessageSummary } from '../../common/helpers/renderMessageText'; import useMessageMediaHash from '../../../hooks/media/useMessageMediaHash'; import useThumbnail from '../../../hooks/media/useThumbnail'; +import useLang from '../../../hooks/useLang'; import useMedia from '../../../hooks/useMedia'; -import useOldLang from '../../../hooks/useOldLang'; import Icon from '../../common/icons/Icon'; import StatisticsRecentPostMeta from './StatisticsRecentPostMeta'; @@ -29,7 +29,7 @@ export type OwnProps = { }; const StatisticsRecentMessage: FC = ({ postStatistic, message }) => { - const lang = useOldLang(); + const lang = useLang(); const { toggleMessageStatistics } = getActions(); const thumbDataUri = useThumbnail(message); @@ -54,7 +54,11 @@ const StatisticsRecentMessage: FC = ({ postStatistic, message }) => { {renderSummary(lang, message, mediaBlobUrl || thumbDataUri, isRoundVideo)}
- {lang('ChannelStats.ViewsCount', postStatistic.viewsCount, 'i')} + {lang( + 'ChannelStatsViewsCount', + { count: postStatistic.viewsCount }, + { pluralValue: postStatistic.viewsCount }, + )}
@@ -68,7 +72,7 @@ const StatisticsRecentMessage: FC = ({ postStatistic, message }) => { ); }; -function renderSummary(lang: OldLangFn, message: ApiMessage, blobUrl?: string, isRoundVideo?: boolean) { +function renderSummary(lang: LangFn, message: ApiMessage, blobUrl?: string, isRoundVideo?: boolean) { if (!blobUrl) { return renderMessageSummary(lang, message); } diff --git a/src/components/ui/AvatarEditable.tsx b/src/components/ui/AvatarEditable.tsx index b51d98cb1..1d2dc0520 100644 --- a/src/components/ui/AvatarEditable.tsx +++ b/src/components/ui/AvatarEditable.tsx @@ -6,6 +6,8 @@ import { import buildClassName from '../../util/buildClassName'; +import useLang from '../../hooks/useLang'; + import Icon from '../common/icons/Icon'; import CropModal from './CropModal'; @@ -20,7 +22,7 @@ interface OwnProps { } const AvatarEditable: FC = ({ - title = 'Change your profile picture', + title, disabled, isForForum, currentAvatarBlobUrl, @@ -29,6 +31,8 @@ const AvatarEditable: FC = ({ const [selectedFile, setSelectedFile] = useState(); const [croppedBlobUrl, setCroppedBlobUrl] = useState(currentAvatarBlobUrl); + const lang = useLang(); + useEffect(() => { setCroppedBlobUrl(currentAvatarBlobUrl); }, [currentAvatarBlobUrl]); @@ -70,7 +74,7 @@ const AvatarEditable: FC = ({ className={labelClassName} role="button" tabIndex={0} - title={title} + title={title || lang('ChangeYourProfilePicture')} > = ({ accept="image/png, image/jpeg" /> - {croppedBlobUrl && Avatar} + {croppedBlobUrl && } diff --git a/src/components/ui/ConfirmDialog.tsx b/src/components/ui/ConfirmDialog.tsx index e258f5f3c..6ba1bee57 100644 --- a/src/components/ui/ConfirmDialog.tsx +++ b/src/components/ui/ConfirmDialog.tsx @@ -7,7 +7,7 @@ import type { TextPart } from '../../types'; import buildClassName from '../../util/buildClassName'; import useKeyboardListNavigation from '../../hooks/useKeyboardListNavigation'; -import useOldLang from '../../hooks/useOldLang'; +import useLang from '../../hooks/useLang'; import Button from './Button'; import Modal from './Modal'; @@ -38,7 +38,7 @@ const ConfirmDialog: FC = ({ header, text, textParts, - confirmLabel = 'Confirm', + confirmLabel, confirmIsDestructive, isConfirmDisabled, isOnlyConfirm, @@ -49,7 +49,7 @@ const ConfirmDialog: FC = ({ onClose, onCloseAnimationEnd, }) => { - const lang = useOldLang(); + const lang = useLang(); const containerRef = useRef(); @@ -84,7 +84,7 @@ const ConfirmDialog: FC = ({ color={confirmIsDestructive ? 'danger' : 'primary'} disabled={isConfirmDisabled} > - {confirmLabel} + {confirmLabel || lang('GeneralConfirm')} {!isOnlyConfirm && } diff --git a/src/config.ts b/src/config.ts index c3765924f..2dbd5b58f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -284,8 +284,6 @@ export const CONTENT_TYPES_WITH_PREVIEW = new Set([ ...SUPPORTED_VIDEO_CONTENT_TYPES, ]); -export const CONTENT_NOT_SUPPORTED = 'The message is not supported on this version of Telegram.'; - // Taken from https://github.com/telegramdesktop/tdesktop/blob/41d9a9fcbd0c809c60ddbd9350791b1436aff7d9/Telegram/SourceFiles/ui/boxes/choose_language_box.cpp#L28 export const SUPPORTED_TRANSLATION_LANGUAGES = [ // Official diff --git a/src/global/actions/ui/messages.ts b/src/global/actions/ui/messages.ts index d89c9907c..a9886cc4a 100644 --- a/src/global/actions/ui/messages.ts +++ b/src/global/actions/ui/messages.ts @@ -17,8 +17,7 @@ import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment'; import { copyHtmlToClipboard } from '../../../util/clipboard'; import { getCurrentTabId } from '../../../util/establishMultitabRole'; import { compact, findLast } from '../../../util/iteratees'; -import * as langProvider from '../../../util/oldLangProvider'; -import { oldTranslate } from '../../../util/oldLangProvider'; +import { getTranslationFn } from '../../../util/localization'; import parseHtmlAsFormattedText from '../../../util/parseHtmlAsFormattedText'; import { getServerTime } from '../../../util/serverTime'; import versionNotification from '../../../versionNotification.txt'; @@ -414,7 +413,7 @@ addActionHandler('focusMessage', (global, actions, payload): ActionReturnType => const chat = selectChat(global, chatId); if (!chat) { - actions.showNotification({ message: oldTranslate('Conversation.ErrorInaccessibleMessage'), tabId }); + actions.showNotification({ message: { key: 'ErrorFocusInaccessibleMessage' }, tabId }); return undefined; } @@ -719,8 +718,9 @@ addActionHandler('toggleMessageSelection', (global, actions, payload): ActionRet if (global.shouldShowContextMenuHint) { actions.disableContextMenuHint(); actions.showNotification({ - // eslint-disable-next-line @stylistic/max-len - message: `To **edit** or **reply**, close this menu. Then ${IS_TOUCH_ENV ? 'long tap' : 'right click'} on a message.`, + message: { + key: IS_TOUCH_ENV ? 'ContextMenuHintTouch' : 'ContextMenuHintMouse', + }, tabId, }); } @@ -1050,7 +1050,7 @@ addActionHandler('closeSuggestedPostApprovalModal', (global, actions, payload): function copyTextForMessages(global: GlobalState, chatId: string, messageIds: number[]) { const { type: messageListType, threadId } = selectCurrentMessageList(global) || {}; - const lang = langProvider.oldTranslate; + const lang = getTranslationFn(); const chat = selectChat(global, chatId); diff --git a/src/global/helpers/chats.ts b/src/global/helpers/chats.ts index b80b75673..6a995dcac 100644 --- a/src/global/helpers/chats.ts +++ b/src/global/helpers/chats.ts @@ -304,7 +304,7 @@ export function getCanDeleteChat(chat: ApiChat) { return isChatBasicGroup(chat) || ((isChatSuperGroup(chat) || isChatChannel(chat)) && chat.isCreator); } -export function getFolderDescriptionText(lang: OldLangFn, folder: ApiChatFolder, chatsCount?: number) { +export function getFolderDescriptionText(lang: LangFn, folder: ApiChatFolder, chatsCount?: number) { const { excludedChatIds, includedChatIds, bots, groups, contacts, nonContacts, channels, @@ -320,7 +320,7 @@ export function getFolderDescriptionText(lang: OldLangFn, folder: ApiChatFolder, || (excludedChatIds?.length) || (includedChatIds?.length) )) { - return lang('Chats', chatsCount); + return lang('ChatsPlural', { count: chatsCount }, { pluralValue: chatsCount }); } // Otherwise, we return a short description of a single filter diff --git a/src/global/helpers/messageSummary.ts b/src/global/helpers/messageSummary.ts index 7c74a7097..8eb8562a8 100644 --- a/src/global/helpers/messageSummary.ts +++ b/src/global/helpers/messageSummary.ts @@ -3,21 +3,20 @@ import type { TeactNode } from '../../lib/teact/teact'; import type { ApiMediaExtendedPreview, ApiMessage, MediaContent, StatefulMediaContent, } from '../../api/types'; -import type { OldLangFn } from '../../hooks/useOldLang'; import { ApiMessageEntityTypes } from '../../api/types'; -import { CONTENT_NOT_SUPPORTED } from '../../config'; +import { type LangFn } from '../../util/localization'; import trimText from '../../util/trimText'; import { renderTextWithEntities } from '../../components/common/helpers/renderTextWithEntities'; import { - getMessageText, getMessageTranscription, + getMessageTextWithFallback, getMessageTranscription, } from './messages'; const SPOILER_CHARS = ['⠺', '⠵', '⠞', '⠟']; export const TRUNCATED_SUMMARY_LENGTH = 80; export function getMessageSummaryText( - lang: OldLangFn, + lang: LangFn, message: ApiMessage, statefulContent: StatefulMediaContent | undefined, noEmoji = false, @@ -26,16 +25,20 @@ export function getMessageSummaryText( ) { const emoji = !noEmoji && getMessageSummaryEmoji(message); const emojiWithSpace = emoji ? `${emoji} ` : ''; - const text = trimText(getMessageTextWithSpoilers(message, statefulContent), truncateLength); + const text = trimText(getMessageTextWithSpoilers(lang, message, statefulContent), truncateLength); const description = getMessageSummaryDescription(lang, message, statefulContent, text, isExtended) as string; return `${emojiWithSpace}${description}`; } -export function getMessageTextWithSpoilers(message: ApiMessage, statefulContent: StatefulMediaContent | undefined) { +export function getMessageTextWithSpoilers( + lang: LangFn, + message: ApiMessage, + statefulContent: StatefulMediaContent | undefined, +) { const transcription = getMessageTranscription(message); - const textWithoutTranscription = getMessageText(statefulContent?.story || message)?.text; + const textWithoutTranscription = getMessageTextWithFallback(lang, statefulContent?.story || message)?.text; if (!textWithoutTranscription) { return transcription; } @@ -56,7 +59,7 @@ export function getMessageTextWithSpoilers(message: ApiMessage, statefulContent: const spoiler = generateBrailleSpoiler(length); - return `${accText.substr(0, offset)}${spoiler}${accText.substr(offset + length, accText.length)}`; + return `${accText.slice(0, offset)}${spoiler}${accText.slice(offset + length)}`; }, textWithoutTranscription); return transcription ? `${transcription}\n${text}` : text; @@ -111,12 +114,12 @@ export function getMessageSummaryEmoji(message: ApiMessage) { } export function getMediaContentTypeDescription( - lang: OldLangFn, content: MediaContent, statefulContent: StatefulMediaContent | undefined, + lang: LangFn, content: MediaContent, statefulContent: StatefulMediaContent | undefined, ) { return getSummaryDescription(lang, content, statefulContent); } export function getMessageSummaryDescription( - lang: OldLangFn, + lang: LangFn, message: ApiMessage, statefulContent: StatefulMediaContent | undefined, truncatedText?: string | TeactNode, @@ -125,7 +128,7 @@ export function getMessageSummaryDescription( return getSummaryDescription(lang, message.content, statefulContent, message, truncatedText, isExtended); } function getSummaryDescription( - lang: OldLangFn, + lang: LangFn, mediaContent: MediaContent, statefulContent: StatefulMediaContent | undefined, message?: ApiMessage, @@ -166,7 +169,7 @@ function getSummaryDescription( if (message?.groupedId || isPaidMediaAlbum) { hasUsedTruncatedText = true; - summary = truncatedText || lang('lng_in_dlg_album'); + summary = truncatedText || lang('Album'); } if (photo || isPaidMediaSinglePhoto) { @@ -210,7 +213,7 @@ function getSummaryDescription( } if (invoice) { - summary = invoice.extendedMedia ? invoice.title : `${lang('PaymentInvoice')}: ${invoice.description}`; + summary = invoice.extendedMedia ? invoice.title : lang('AttachInvoice', { description: invoice.description }); } if (text) { @@ -222,11 +225,11 @@ function getSummaryDescription( } if (location?.mediaType === 'geo' || location?.mediaType === 'venue') { - summary = lang('Message.Location'); + summary = lang('AttachLocation'); } if (location?.mediaType === 'geoLive') { - summary = lang('Message.LiveLocation'); + summary = lang('AttachLiveLocation'); } if (game) { @@ -234,22 +237,22 @@ function getSummaryDescription( } if (giveaway) { - summary = lang('BoostingGiveawayChannelStarted'); + summary = lang('AttachGiveaway'); } if (giveawayResults) { - summary = lang('Message.GiveawayEndedWinners', giveawayResults.winnersCount); + summary = lang('AttachGiveawayResults'); } if (storyData) { - summary = truncatedText || (message ? lang('ForwardedStory') : lang('Chat.ReplyStory')); + summary = truncatedText || lang('AttachStory'); } if (todo) { - summary = lang('Chat.Todo.Message.Title'); + summary = lang('AttachTodo'); } - return summary || CONTENT_NOT_SUPPORTED; + return summary || lang('MessageUnsupported'); } export function generateBrailleSpoiler(length: number) { diff --git a/src/global/helpers/messages.ts b/src/global/helpers/messages.ts index 4137b4e0e..75d1cc4ae 100644 --- a/src/global/helpers/messages.ts +++ b/src/global/helpers/messages.ts @@ -17,7 +17,6 @@ import type { GlobalState } from '../types'; import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../../api/types'; import { - CONTENT_NOT_SUPPORTED, LOTTIE_STICKER_MIME_TYPE, RE_LINK_TEMPLATE, SERVICE_NOTIFICATIONS_USER_ID, @@ -95,7 +94,11 @@ export function groupStatefulContent({ } export function getMessageText(message: MediaContainer) { - return hasMessageText(message) ? message.content.text || { text: CONTENT_NOT_SUPPORTED } : undefined; + return hasMessageText(message) ? message.content.text : undefined; +} + +export function getMessageTextWithFallback(lang: LangFn, message: MediaContainer) { + return hasMessageText(message) ? message.content.text || { text: lang('MessageUnsupported') } : undefined; } export function getMessageCustomShape(message: ApiMessage): boolean { diff --git a/src/global/helpers/renderMessageSummaryHtml.ts b/src/global/helpers/renderMessageSummaryHtml.ts index 846f95ee2..b2dc71ff2 100644 --- a/src/global/helpers/renderMessageSummaryHtml.ts +++ b/src/global/helpers/renderMessageSummaryHtml.ts @@ -1,13 +1,13 @@ import type { ApiMessage } from '../../api/types'; -import type { OldLangFn } from '../../hooks/useOldLang'; +import { type LangFn } from '../../util/localization'; import { renderMessageText } from '../../components/common/helpers/renderMessageText'; import { getGlobal } from '..'; import { getMessageStatefulContent } from './messages'; import { getMessageSummaryDescription, getMessageSummaryEmoji } from './messageSummary'; export function renderMessageSummaryHtml( - lang: OldLangFn, + lang: LangFn, message: ApiMessage, ) { const global = getGlobal(); diff --git a/src/types/language.d.ts b/src/types/language.d.ts index 7b93c7834..16c00b63c 100644 --- a/src/types/language.d.ts +++ b/src/types/language.d.ts @@ -58,6 +58,7 @@ export interface LangPair { 'PremiumLimitAccountsNoPremium': undefined; 'PremiumLimitAccounts': undefined; 'SendMessage': undefined; + 'MessageUnsupported': undefined; 'ConversationDefaultRestrictedMedia': undefined; 'AccDescrVoiceMessage': undefined; 'BotSettings': undefined; @@ -111,6 +112,7 @@ export interface LangPair { 'UserRestrictionsNoChangeInfo': undefined; 'UserRestrictionsInviteUsers': undefined; 'UserRestrictionsPinMessages': undefined; + 'ChatPermissionNotAvailable': undefined; 'StatsMessageInteractionsTitle': undefined; 'StatsGroupGrowthTitle': undefined; 'StatsGroupMembersTitle': undefined; @@ -424,6 +426,7 @@ export interface LangPair { 'AlwaysShareWith': undefined; 'NeverShareWith': undefined; 'SessionsTitle': undefined; + 'SessionTerminate': undefined; 'OtherWebSessions': undefined; 'BlockedUsers': undefined; 'TwoStepVerification': undefined; @@ -608,6 +611,7 @@ export interface LangPair { 'SettingsPerformanceStickerEffects': undefined; 'SettingsPerformanceAutoplayGif': undefined; 'SettingsPerformanceAutoplayVideo': undefined; + 'SettingsPerformanceGranularTitle': undefined; 'FavoriteStickers': undefined; 'PremiumStickers': undefined; 'GroupStickers': undefined; @@ -627,7 +631,6 @@ export interface LangPair { 'ErrorUnspecified': undefined; 'NoStickers': undefined; 'ClearRecentEmoji': undefined; - 'TextFormatAddLinkTitle': undefined; 'Save': undefined; 'ConversationEmptyPlaceholder': undefined; 'ConversationGreetingText': undefined; @@ -832,8 +835,16 @@ export interface LangPair { 'ChannelPermissionsHeader': undefined; 'UserRestrictionsSend': undefined; 'UserRestrictionsSendMedia': undefined; - 'UserRestrictionsSendStickers': undefined; - 'UserRestrictionsSendPolls': undefined; + 'UserRestrictionsCreateTopics': undefined; + 'SendMediaPermissionFiles': undefined; + 'SendMediaPermissionPhotos': undefined; + 'SendMediaPermissionVideos': undefined; + 'SendMediaPermissionStickersGifs': undefined; + 'SendMediaPermissionAudios': undefined; + 'SendMediaPermissionVoices': undefined; + 'SendMediaPermissionRoundVideos': undefined; + 'SendMediaPermissionWebPages': undefined; + 'SendMediaPermissionPolls': undefined; 'UserRestrictionsEmbedLinks': undefined; 'UserRestrictionsChangeInfo': undefined; 'ChannelAddException': undefined; @@ -944,7 +955,7 @@ export interface LangPair { 'FilterContacts': undefined; 'FilterNonContacts': undefined; 'FromYou': undefined; - 'InDlgAlbum': undefined; + 'Album': undefined; 'AttachPhoto': undefined; 'AttachGif': undefined; 'AttachVideo': undefined; @@ -952,8 +963,10 @@ export interface LangPair { 'AttachMusic': undefined; 'AttachContact': undefined; 'AttachStory': undefined; - 'MessageLocation': undefined; - 'MessageLiveLocation': undefined; + 'AttachLocation': undefined; + 'AttachGiveaway': undefined; + 'AttachGiveawayResults': undefined; + 'AttachTodo': undefined; 'ServiceNotifications': undefined; 'Bot': undefined; 'ALongTimeAgo': undefined; @@ -1086,6 +1099,7 @@ export interface LangPair { 'SettingsPasscodeStart1': undefined; 'SettingsPasscodeStart2': undefined; 'CurrentPasswordPlaceholder': undefined; + 'ChangeYourProfilePicture': undefined; 'TooManyTabsTitle': undefined; 'TooManyTabsDescription': undefined; 'TooManyTabsReload': undefined; @@ -1141,6 +1155,7 @@ export interface LangPair { 'FormattingMonospaceAria': undefined; 'FormattingUnderlineAria': undefined; 'FormattingStrikethroughAria': undefined; + 'FormattingAddLinkAria': undefined; 'FormattingEnterUrl': undefined; 'PreviewWebPageClose': undefined; 'MediaLocaltionImageAlt': undefined; @@ -1190,6 +1205,8 @@ export interface LangPair { 'ReplyInPrivateMessage': undefined; 'ProfileOpenAppTerms': undefined; 'ProfileBotOpenAppInfoLink': undefined; + 'ProfileBirthday': undefined; + 'ProfileBirthdayToday': undefined; 'MonetizationInfoTONTitle': undefined; 'AriaSearchOlderResult': undefined; 'AriaSearchNewerResult': undefined; @@ -1339,6 +1356,9 @@ export interface LangPair { 'SearchTabVoice': undefined; 'SearchTabMessages': undefined; 'SearchTabPublicPosts': undefined; + 'SearchResultTopics': undefined; + 'SearchResultMyChannels': undefined; + 'SearchResultRecommendedChannels': undefined; 'StarsTransactionsAll': undefined; 'StarsTransactionsIncoming': undefined; 'StarsTransactionsOutgoing': undefined; @@ -1392,6 +1412,8 @@ export interface LangPair { 'CheckPasswordTitle': undefined; 'CheckPasswordPlaceholder': undefined; 'CheckPasswordDescription': undefined; + 'PasswordFormPlaceholder': undefined; + 'PasswordFormSubmit': undefined; 'ActionFallbackUser': undefined; 'ActionFallbackChat': undefined; 'ActionFallbackChannel': undefined; @@ -1655,6 +1677,9 @@ export interface LangPair { 'RatingNegativeLevel': undefined; 'LinkDescriptionRatingBack': undefined; 'LinkDescriptionRatingPreview': undefined; + 'ErrorFocusInaccessibleMessage': undefined; + 'ContextMenuHintMouse': undefined; + 'ContextMenuHintTouch': undefined; } export interface LangPairWithVariables { @@ -1901,6 +1926,9 @@ export interface LangPairWithVariables { 'NewDiscussionChatTitle': { 'name': V; }; + 'AttachInvoice': { + 'description': V; + }; 'LastSeenTodayAt': { 'time': V; }; @@ -1973,6 +2001,20 @@ export interface LangPairWithVariables { 'ProfileOpenAppAbout': { 'terms': V; }; + 'ProfileBirthdayValue': { + 'date': V; + }; + 'ProfileBirthdayValueYear': { + 'date': V; + 'age': V; + }; + 'ProfileBirthdayTodayValue': { + 'date': V; + }; + 'ProfileBirthdayTodayValueYear': { + 'date': V; + 'age': V; + }; 'ChannelEarnLearnCoinAbout': { 'link': V; }; @@ -2135,6 +2177,9 @@ export interface LangPairWithVariables { 'StarsReactionTerms': { 'link': V; }; + 'AriaMiniApp': { + 'bot': V; + }; 'StarsSubscribeInfo': { 'link': V; }; @@ -2545,8 +2590,8 @@ export interface LangPairWithVariables { 'amount': V; }; 'ActionPaidOneMessageIncoming': { - 'amount': V; 'user': V; + 'amount': V; }; 'PaneMessagePaidMessageCharge': { 'peer': V; @@ -2688,12 +2733,10 @@ export interface LangPairWithVariables { }; 'SuggestedPostReceiveAmount': { 'peer': V; - 'currency': V; 'duration': V; }; 'SuggestedPostReceiveAmountYou': { 'peer': V; - 'currency': V; 'duration': V; }; 'SuggestedPostRefund': { @@ -2703,7 +2746,6 @@ export interface LangPairWithVariables { 'SuggestedPostRefundYou': { 'peer': V; 'duration': V; - 'currency': V; }; 'SuggestedPostBalanceTooLow': { 'peer': V; @@ -2748,7 +2790,6 @@ export interface LangPairWithVariables { }; 'SuggestedPostConfirmDetailsUser': { 'amount': V; - 'commission': V; 'duration': V; }; 'SuggestedPostConfirmDetailsWithTimeAdmin': { @@ -2759,7 +2800,6 @@ export interface LangPairWithVariables { }; 'SuggestedPostConfirmDetailsWithTimeUser': { 'amount': V; - 'commission': V; 'time': V; 'duration': V; }; @@ -2819,9 +2859,6 @@ export interface LangPairWithVariables { 'tasks': V; 'list': V; }; - 'HintTodoListTasksCount': { - 'count': V; - }; 'GiftInfoCollectibleBy': { 'number': V; 'owner': V; @@ -2832,12 +2869,6 @@ export interface LangPairWithVariables { 'ButtonSensitiveAlways': { 'years': V; }; - 'NotificationGiftsLimit': { - 'count': V; - }; - 'DescriptionGiftPremiumRequired': { - 'count': V; - }; 'DescriptionComposerGiftMinimumCurrencyPrice': { 'amount': V; }; @@ -2984,6 +3015,9 @@ export interface LangPairPluralWithVariables { 'ChannelStatsSharesCount': { 'count': V; }; + 'ChatsPlural': { + 'count': V; + }; 'LastSeenMinutesAgo': { 'count': V; }; @@ -3187,9 +3221,18 @@ export interface LangPairPluralWithVariables { 'MessageActionTodoTaskCount': { 'count': V; }; + 'HintTodoListTasksCount2': { + 'count': V; + }; 'TextAgeVerificationModal': { 'count': V; }; + 'NotificationGiftsLimit2': { + 'count': V; + }; + 'DescriptionGiftPremiumRequired2': { + 'count': V; + }; 'RemainingPublicPostsSearch': { 'count': V; };