diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 40cb3d5448..9d0c7f18a1 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -13887,7 +13887,11 @@ Sorry for the inconvenience."; "Chat.NonContactUser.UpdatedName" = "User updated name %1$@"; "Chat.NonContactUser.UpdatedPhoto" = "User updated photo %1$@"; -"Chat.NonContactUser.UpdatedToday" = "today"; + +"Chat.NonContactUser.UpdatedMinutes_1" = "%@ minute ago"; +"Chat.NonContactUser.UpdatedMinutes_any" = "%@ minutes ago"; +"Chat.NonContactUser.UpdatedHours_1" = "%@ hour ago"; +"Chat.NonContactUser.UpdatedHours_any" = "%@ hours ago"; "Chat.NonContactUser.UpdatedDays_1" = "%@ day ago"; "Chat.NonContactUser.UpdatedDays_any" = "%@ days ago"; @@ -13933,3 +13937,39 @@ Sorry for the inconvenience."; "PeerInfo.Gifts.ToastUnpinned.Text" = "Gift Unpinned."; "PeerInfo.Gifts.ToastPinned.Title" = "Gift Pinned"; "PeerInfo.Gifts.ToastPinned.Text" = "Now it will always be shown on the top."; + +"Chat.PaidMessage.Confirm.Title" = "Confirm Payment"; +"Chat.PaidMessage.Confirm.DontAskAgain" = "Don't ask again"; +"Chat.PaidMessage.Confirm.PayForMessage_1" = "Pay for %@ Message"; +"Chat.PaidMessage.Confirm.PayForMessage_any" = "Pay for %@ Messages"; +"Chat.PaidMessage.Confirm.Single.Text" = "**%1$@** charges **%2$@** per incoming message. Would you like to pay **%3$@** to send %4$@?"; +"Chat.PaidMessage.Confirm.Multiple.Text" = "You selected %1$@ who charge Stars for messages. Would you like to pay **%2$@** Stars to send %3$@?"; +"Chat.PaidMessage.Confirm.Text.Users_1" = "**%@** user"; +"Chat.PaidMessage.Confirm.Text.Users_any" = "**%@** users"; +"Chat.PaidMessage.Confirm.Text.Messages_1" = "**%@** message"; +"Chat.PaidMessage.Confirm.Text.Messages_any" = "**%@** messages"; +"Chat.PaidMessage.Confirm.Text.Stars_1" = "%@ Star"; +"Chat.PaidMessage.Confirm.Text.Stars_any" = "%@ Stars"; + +"Chat.PaidMessage.RemoveFee.Title" = "Remove Fee"; +"Chat.PaidMessage.RemoveFee.Text" = "Are you sure you want to allow **%@** to message you for free?"; +"Chat.PaidMessage.RemoveFee.Yes" = "Yes"; +"Chat.PaidMessage.RemoveFee.Refund" = "Refund already paid **%@**"; +"Chat.PaidMessage.RemoveFee.Refund.Stars_1" = "%@ Star"; +"Chat.PaidMessage.RemoveFee.Refund.Stars_any" = "%@ Stars"; + +"Chat.PaidMessage.Sent.Title_1" = "Message Sent"; +"Chat.PaidMessage.Sent.Title_any" = "%@ Messages Sent"; +"Chat.PaidMessage.Sent.Text" = "You paid %@"; +"Chat.PaidMessage.Sent.Text.Stars_1" = "%@ Star"; +"Chat.PaidMessage.Sent.Text.Stars_any" = "%@ Stars"; + +"Chat.PaidMessageFee.Text" = "%1$@ must pay %2$@ for each message to you."; +"Chat.PaidMessageFee.RemoveFee" = "Remove Fee"; + +"Privacy.Review.Review" = "Review"; +"Privacy.Review.Calls.Title" = "Call Settings"; +"Privacy.Review.Calls.Text" = "You've restricted who can message you, but anyone can still call you. Would you like to review these settings?"; + +"Privacy.Review.Invite.Title" = "Invitation Settings"; +"Privacy.Review.Invite.Text" = "You've restricted who can message you, but anyone can still invite you to groups and channels. Would you like to review these settings?"; diff --git a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift index d87b446b84..25da592f9b 100644 --- a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift +++ b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift @@ -973,7 +973,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS text = presentationInterfaceState.strings.MediaPicker_Send } actionButtonsSize = self.actionButtons.updateLayout(size: CGSize(width: 44.0, height: minimalHeight), transition: transition, minimized: isMinimized, text: text, interfaceState: presentationInterfaceState) - textBackgroundInset = 44.0 - actionButtonsSize.width + textBackgroundInset = actionButtonsSize.width - 44.0 } else { actionButtonsSize = CGSize(width: 44.0, height: minimalHeight) } @@ -981,11 +981,11 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS let actionButtonsFrame = CGRect(origin: CGPoint(x: width - rightInset - actionButtonsSize.width + 1.0 - UIScreenPixel + composeButtonsOffset, y: panelHeight - minimalHeight), size: actionButtonsSize) transition.updateFrame(node: self.actionButtons, frame: actionButtonsFrame) - let textInputBackgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: textInputFrame.size.width + composeButtonsOffset + textBackgroundInset, height: textInputFrame.size.height)) + let textInputBackgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: textInputFrame.size.width + composeButtonsOffset, height: textInputFrame.size.height)) transition.updateFrame(node: self.textInputContainerBackgroundNode, frame: textInputBackgroundFrame) - transition.updateFrame(layer: self.textInputBackgroundNode.layer, frame: CGRect(x: leftInset + textFieldInsets.left, y: textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + composeButtonsOffset + textBackgroundInset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)) - transition.updateFrame(layer: self.textInputBackgroundImageNode.layer, frame: CGRect(x: 0.0, y: 0.0, width: baseWidth - textFieldInsets.left - textFieldInsets.right + composeButtonsOffset + textBackgroundInset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)) + transition.updateFrame(layer: self.textInputBackgroundNode.layer, frame: CGRect(x: leftInset + textFieldInsets.left, y: textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + composeButtonsOffset - textBackgroundInset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)) + transition.updateFrame(layer: self.textInputBackgroundImageNode.layer, frame: CGRect(x: 0.0, y: 0.0, width: baseWidth - textFieldInsets.left - textFieldInsets.right + composeButtonsOffset - textBackgroundInset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)) var textInputViewRealInsets = UIEdgeInsets() if let presentationInterfaceState = self.presentationInterfaceState { diff --git a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift index f33f401371..28784bb729 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift @@ -1470,16 +1470,15 @@ public func privacyAndSecurityController( } showPrivacySuggestionImpl = { - //TODO:localize let presentationData = context.sharedContext.currentPresentationData.with { $0 } if reviewCallPrivacySuggestion { reviewCallPrivacySuggestion = false let alertController = textAlertController( context: context, - title: "Call Settings", - text: "You've restricted who can message you, but anyone can still call you. Would you like to review these settings?", + title: presentationData.strings.Privacy_Review_Calls_Title, + text: presentationData.strings.Privacy_Review_Calls_Text, actions: [ - TextAlertAction(type: .defaultAction, title: "Review", action: { + TextAlertAction(type: .defaultAction, title: presentationData.strings.Privacy_Review_Review, action: { arguments.openVoiceCallPrivacy() }), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { @@ -1495,10 +1494,10 @@ public func privacyAndSecurityController( reviewInvitePrivacySuggestion = false let alertController = textAlertController( context: context, - title: "Invitation Settings", - text: "You've restricted who can message you, but anyone can still invite you to groups and channels. Would you like to review these settings?", + title: presentationData.strings.Privacy_Review_Invite_Title, + text: presentationData.strings.Privacy_Review_Invite_Text, actions: [ - TextAlertAction(type: .defaultAction, title: "Review", action: { + TextAlertAction(type: .defaultAction, title: presentationData.strings.Privacy_Review_Review, action: { arguments.openGroupsPrivacy() }), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { diff --git a/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift b/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift index 22db5b1017..8a8176e703 100644 --- a/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift @@ -659,3 +659,15 @@ public func stringForRemainingMuteInterval(strings: PresentationStrings, muteInt return strings.MuteExpires_Days(Int32(round(Float(value) / (24 * 60 * 60)))) } } + +public func stringForIntervalSinceUpdateAction(strings: PresentationStrings, value: Int32) -> String { + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + let value = max(1 * 60, timestamp - value) + if value <= 1 * 60 * 60 { + return strings.Chat_NonContactUser_UpdatedMinutes(Int32(round(Float(value) / 60))) + } else if value <= 24 * 60 * 60 { + return strings.Chat_NonContactUser_UpdatedHours(Int32(round(Float(value) / (60 * 60)))) + } else { + return strings.Chat_NonContactUser_UpdatedDays(Int32(round(Float(value) / (24 * 60 * 60)))) + } +} diff --git a/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift b/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift index 46a17c495e..7a4accac0c 100644 --- a/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift +++ b/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift @@ -1283,8 +1283,7 @@ final class AvatarEditorScreenComponent: Component { case .suggest: buttonText = strings.AvatarEditor_SuggestProfilePhoto case .user: - //TODO:localize - buttonText = "Set My Photo" //strings.AvatarEditor_SetProfilePhoto + buttonText = strings.AvatarEditor_SetProfilePhoto case .group, .forum: buttonText = strings.AvatarEditor_SetGroupPhoto case .channel: diff --git a/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift b/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift index ec77b0a7c1..c769e996f4 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift @@ -424,17 +424,9 @@ public func chatMessagePaymentAlertController( var completionImpl: (() -> Void)? var dismissImpl: (() -> Void)? - //TODO:localize - let title = "Confirm Payment" - let actionTitle: String - let messagesString: String - if count > 1 { - messagesString = "**\(count)** messages" - actionTitle = "Pay for \(count) Messages" - } else { - messagesString = "**\(count)** message" - actionTitle = "Pay for 1 Message" - } + let title = presentationData.strings.Chat_PaidMessage_Confirm_Title + let actionTitle = presentationData.strings.Chat_PaidMessage_Confirm_PayForMessage(count) + let messagesString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Messages(count) let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: actionTitle, action: { completionImpl?() @@ -442,17 +434,20 @@ public func chatMessagePaymentAlertController( }), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { dismissImpl?() })] - let text: String if peers.count == 1, let peer = peers.first { - text = "**\(peer.compactDisplayTitle)** charges **\(amount.value) Stars** per incoming message. Would you like to pay **\(amount.value * Int64(count)) Stars** to send \(messagesString)?" + let amountString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(amount.value)) + let totalString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(amount.value * Int64(count))) + text = presentationData.strings.Chat_PaidMessage_Confirm_Single_Text(peer.compactDisplayTitle, amountString, totalString, messagesString).string } else { let amount = totalAmount ?? amount - text = "You selected **\(peers.count)** users who charge Stars for messages. Would you like to pay **\(amount.value)** Stars to send \(messagesString)?" + let usersString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Users(Int32(peers.count)) + let totalString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(amount.value * Int64(count))) + text = presentationData.strings.Chat_PaidMessage_Confirm_Multiple_Text(usersString, totalString, messagesString).string } - let optionText = hasCheck ? "Don't ask again" : nil + let optionText = hasCheck ? presentationData.strings.Chat_PaidMessage_Confirm_DontAskAgain : nil let contentNode = ChatMessagePaymentAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, title: title, text: text, optionText: optionText, actions: actions, alignment: .vertical) @@ -470,8 +465,6 @@ public func chatMessagePaymentAlertController( return controller } - - public func chatMessageRemovePaymentAlertController( context: AccountContext? = nil, presentationData: PresentationData, @@ -488,20 +481,19 @@ public func chatMessageRemovePaymentAlertController( var completionImpl: (() -> Void)? var dismissImpl: (() -> Void)? - //TODO:localize let actions: [TextAlertAction] = [ - TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { + TextAlertAction(type: .genericAction, title: strings.Common_Cancel, action: { dismissImpl?() }), - TextAlertAction(type: .defaultAction, title: "Yes", action: { + TextAlertAction(type: .defaultAction, title: strings.Chat_PaidMessage_RemoveFee_Yes, action: { completionImpl?() dismissImpl?() }) ] - let title = "Remove Fee" - let text = "Are you sure you want to allow **\(peer.compactDisplayTitle)** to message you for free?" - let optionText = amount.flatMap { "Refund already paid **\($0.value) Stars**" } + let title = strings.Chat_PaidMessage_RemoveFee_Title + let text = strings.Chat_PaidMessage_RemoveFee_Text(peer.compactDisplayTitle).string + let optionText = amount.flatMap { strings.Chat_PaidMessage_RemoveFee_Refund(strings.Chat_PaidMessage_RemoveFee_Refund_Stars(Int32($0.value))).string } let contentNode = ChatMessagePaymentAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, title: title, text: text, optionText: optionText, actions: actions, alignment: .horizontal) diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift index 0e1b9de5e6..22335c4025 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift @@ -21,12 +21,14 @@ extension ChatControllerImpl { return } if let sendPaidMessageStars = self.presentationInterfaceState.sendPaidMessageStars { + let totalAmount = sendPaidMessageStars.value * Int64(count) + let _ = (ApplicationSpecificNotice.dismissedPaidMessageWarningNamespace(accountManager: self.context.sharedContext.accountManager, peerId: peer.id) |> deliverOnMainQueue).start(next: { [weak self] dismissedAmount in guard let self, let starsContext = self.context.starsContext else { return } - if let dismissedAmount, dismissedAmount == sendPaidMessageStars.value, let currentState = starsContext.currentState, currentState.balance > sendPaidMessageStars { + if let dismissedAmount, dismissedAmount == sendPaidMessageStars.value, let currentState = starsContext.currentState, currentState.balance.value > totalAmount, count < 3 && totalAmount < 100 { completion(true) self.displayPaidMessageUndo(count: count, amount: sendPaidMessageStars) } else { @@ -52,14 +54,14 @@ extension ChatControllerImpl { let _ = ApplicationSpecificNotice.setDismissedPaidMessageWarningNamespace(accountManager: self.context.sharedContext.accountManager, peerId: peer.id, amount: sendPaidMessageStars.value).start() } - if let currentState = starsContext.currentState, currentState.balance < sendPaidMessageStars { + if let currentState = starsContext.currentState, currentState.balance.value < totalAmount { let _ = (self.context.engine.payments.starsTopUpOptions() |> take(1) |> deliverOnMainQueue).startStandalone(next: { [weak self] options in guard let self else { return } - let controller = self.context.sharedContext.makeStarsPurchaseScreen(context: self.context, starsContext: starsContext, options: options, purpose: .sendMessage(peerId: peer.id, requiredStars: sendPaidMessageStars.value), completion: { _ in + let controller = self.context.sharedContext.makeStarsPurchaseScreen(context: self.context, starsContext: starsContext, options: options, purpose: .sendMessage(peerId: peer.id, requiredStars: totalAmount), completion: { _ in completion(false) }) self.push(controller) @@ -89,18 +91,11 @@ extension ChatControllerImpl { self.context.engine.messages.forceSendPostponedPaidMessage(peerId: peerId) } - //TODO:localize - let title: String - if count > 1 { - title = "\(count) Messages Sent" - } else { - title = "Message Sent" - } - + let title = self.presentationData.strings.Chat_PaidMessage_Sent_Title(count) + let text = self.presentationData.strings.Chat_PaidMessage_Sent_Text(self.presentationData.strings.Chat_PaidMessage_Sent_Text_Stars(Int32(amount.value * Int64(count)))).string let textItems: [AnimatedTextComponent.Item] = [ - AnimatedTextComponent.Item(id: 0, content: .text("You paid \(amount.value * Int64(count)) Stars")) + AnimatedTextComponent.Item(id: 0, content: .text(text)) ] - let controller = UndoOverlayController(presentationData: self.presentationData, content: .starsSent(context: self.context, title: title, text: textItems), elevatedLayout: false, position: .top, action: { [weak self] action in guard let self else { return false diff --git a/submodules/TelegramUI/Sources/ChatFeePanelNode.swift b/submodules/TelegramUI/Sources/ChatFeePanelNode.swift index dc3504cde7..c5641e9fb9 100644 --- a/submodules/TelegramUI/Sources/ChatFeePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatFeePanelNode.swift @@ -89,14 +89,13 @@ final class ChatFeePanelNode: ASDisplayNode { if self.theme !== interfaceState.theme { self.theme = interfaceState.theme self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor - //TODO:localize - self.removeTextNode.attributedText = NSAttributedString(string: "Remove Fee", font: Font.regular(17.0), textColor: interfaceState.theme.chat.inputPanel.panelControlAccentColor) + self.removeTextNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PaidMessageFee_RemoveFee, font: Font.regular(17.0), textColor: interfaceState.theme.chat.inputPanel.panelControlAccentColor) } let paidMessageStars = interfaceState.contactStatus?.peerStatusSettings?.paidMessageStars?.value ?? 0 if let peer = interfaceState.renderedPeer?.peer.flatMap(EnginePeer.init) { - let attributedText = NSMutableAttributedString(string: "\(peer.compactDisplayTitle) must pay ⭐️\(paidMessageStars) for each message to you.", font: Font.regular(12.0), textColor: interfaceState.theme.rootController.navigationBar.secondaryTextColor) + let attributedText = NSMutableAttributedString(string: interfaceState.strings.Chat_PaidMessageFee_Text(peer.compactDisplayTitle, "⭐️\(paidMessageStars)").string, font: Font.regular(12.0), textColor: interfaceState.theme.rootController.navigationBar.secondaryTextColor) let range = (attributedText.string as NSString).range(of: "⭐️") if range.location != NSNotFound { attributedText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: true)), range: range) diff --git a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift index f7ee8f4b59..7e126d9e4f 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift @@ -11,6 +11,7 @@ import ChatMessageItemCommon import TextFormat import Markdown import Display +import TelegramStringFormatting struct ChatHistoryEntriesForViewState { private var messageStableIdToLocalId: [UInt32: Int64] = [:] @@ -442,11 +443,8 @@ func chatHistoryEntriesForView( if peerStatusSettings.flags.contains(.canAddContact) || peerStatusSettings.flags.contains(.canReport) || peerStatusSettings.flags.contains(.canBlock) { if let chatPeer, let photoChangeDate = peerStatusSettings.photoChangeDate, photoChangeDate > 0 { - let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - let days = Int32(floor(Float(currentTime - photoChangeDate) / 86400.0)) - let text = presentationData.strings.Chat_NonContactUser_UpdatedPhoto( - days == 0 ? presentationData.strings.Chat_NonContactUser_UpdatedToday : presentationData.strings.Chat_NonContactUser_UpdatedDays(days) - ) + let timeText = stringForIntervalSinceUpdateAction(strings: presentationData.strings, value: photoChangeDate) + let text = presentationData.strings.Chat_NonContactUser_UpdatedPhoto(timeText) var entities: [MessageTextEntity] = [] for range in text.ranges { entities.append(MessageTextEntity(range: range.range.lowerBound ..< range.range.upperBound, type: .Bold)) @@ -485,11 +483,8 @@ func chatHistoryEntriesForView( } if let chatPeer, let nameChangeDate = peerStatusSettings.nameChangeDate, nameChangeDate > 0 { - let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - let days = Int32(floor(Float(currentTime - nameChangeDate) / 86400.0)) - let text = presentationData.strings.Chat_NonContactUser_UpdatedName( - days == 0 ? presentationData.strings.Chat_NonContactUser_UpdatedToday : presentationData.strings.Chat_NonContactUser_UpdatedDays(days) - ) + let timeText = stringForIntervalSinceUpdateAction(strings: presentationData.strings, value: nameChangeDate) + let text = presentationData.strings.Chat_NonContactUser_UpdatedName(timeText) var entities: [MessageTextEntity] = [] for range in text.ranges { entities.append(MessageTextEntity(range: range.range.lowerBound ..< range.range.upperBound, type: .Bold))