Update localization

This commit is contained in:
Isaac 2024-03-28 18:38:13 +04:00
parent a6ecfd96a4
commit 6dd93afd32
26 changed files with 249 additions and 247 deletions

View File

@ -11760,3 +11760,125 @@ Sorry for the inconvenience.";
"Chat.ContextMenu.AboutAd" = "About This Ad";
"Chat.ContextMenu.ReportAd" = "Report Ad";
"Chat.ContextMenu.RemoveAd" = "Remove Ad";
"Settings.BotListSettings" = "Bot Settings";
"Settings.BotSettings.Biometry" = "Biometry";
"PrivacySettings.ValueCloseFriendsAndPremium" = "Close Friends, Premium";
"PrivacySettings.ValueCloseFriendsAndPremiumPlus" = "Close Friends, Premium +%@";
"PrivacySettings.ValuePremium" = "Premium Users";
"PrivacySettings.ValuePremiumPlus" = "Premium Users +%@";
"PrivacySettings.ValuePremiumAndContacts" = "Premium & Contacts";
"PrivacySettings.InviteItem" = "Invites";
"PrivacySettings.InviteSectionFooter" = "You can restrict which users are allowed to add you to groups and channels.";
"PrivacySettings.CategoryPremiumUsers" = "Premium Users";
"PrivacySettings.SearchUserTypesHeader" = "USER TYPES";
"PrivacySettings.SearchUsersTitle" = "Add Users";
"PrivacySettings.SearchUsersPlaceholder" = "Search users and groups";
"Business.Links.PreviewTitle" = "Link to Chat";
"Business.Links.PreviewText" = "Add a message that will be entered in the message input field for anyone who starts a chat with you using this link:";
"Chat.EmptyStateIntroFooter" = "%@ added the message above for all empty chats";
"Chat.EmptyStateIntroFooterAction" = "how?";
"Chat.EmptyStateIntroFooterPremiumActionButton" = "OK";
"Settings.PersonalChannelItem" = "Channel";
"Settings.PersonalChannelEmptyValue" = "Add";
"Settings.PersonalChannelAddedToast" = "Personal channel added.";
"Settings.PersonalChannelUpdatedToast" = "Personal channel updated.";
"Settings.PersonalChannelRemovedToast" = "Personal channel removed.";
"Settings.PersonalChannelSelectTitle" = "Channel";
"Settings.PersonalChannelSelectSubtitle" = "select your channel";
"Settings.PersonalChannelRemove" = "Hide Channel";
"Profile.PersonalChannelSectionTitle" = "CHANNEL";
"SendInviteLink.TitleUpgradeToPremium" = "Upgrade to Premium";
"SendInviteLink.TextContactsAndPremiumOneUser" = "**%@** accepts invitations to groups from contacts and **Premium** users.";
"SendInviteLink.TextContactsAndPremiumMultipleUsers_1" = "{user_list}, and **%d** more person only accept invitations to groups from contacts and **Premium** users.";
"SendInviteLink.TextContactsAndPremiumMultipleUsers_any" = "{user_list}, and **%d** more people only accept invitations to groups from contacts and **Premium** users.";
"SendInviteLink.SubscribeToPremiumButton" = "Subscribe to Telegram Premium";
"SendInviteLink.PremiumOrSendSectionSeparator" = "or";
"SendInviteLink.TextSendInviteLink" = "You can try to send an invite link instead.";
"SendInviteLink.StatusAvailableToPremiumOnly" = "Available only to premium users";
"Business.Links.ItemNoClicks" = "no clicks";
"Business.Links.ItemClickCount_1" = "1 click";
"Business.Links.ItemClickCount_any" = "%2 clicks";
"Business.Links.ItemNoText" = "No text";
"Business.Links.ItemActionShare" = "Share";
"Business.Links.ErrorTooManyLinks" = "You can't create more links";
"Business.Links.DeleteItemConfirmationAction" = "Delete Link";
"Business.Links.Text" = "Give your customers short links that start a chat with you — and suggest the first message from them to you.";
"Business.Links.CreateAction" = "Create a Link to Chat";
"Business.Links.LinksSectionHeader" = "LINKS TO CHAT";
"Business.Links.SimpleLinkInfoUsernamePhone" = "You can also use a simple link for a chat with you — [t.me/%1$@](username) or [t.me/\u{2060}+\u{2060}%2$@](phone).";
"Business.Links.SimpleLinkInfoUsername" = "You can also use a simple link for a chat with you — [t.me/%@](username).";
"Business.Links.SimpleLinkInfoPhone" = "You can also use a simple link for a chat with you — [t.me/\u{2060}+\u{2060}%@](phone).";
"Business.Links.LinkNameTitle" = "Link Name";
"Business.Links.LinkNameText" = "Add a name for this link that only you will see.";
"Business.Links.LinkNameInputPlaceholder" = "Name this link...";
"Business.Links.AlertUnsavedText" = "You have unsaved changes. Reset?";
"Business.Links.AlertUnsavedAction" = "Reset";
"Business.Links.EditLinkTitle" = "Link to Chat";
"Business.Links.EditLinkToastSaved" = "Preset message saved.";
"Business.Intro.Title" = "Intro";
"Business.Intro.IntroTitlePlaceholder" = "Title";
"Business.Intro.IntroTextPlaceholder" = "Enter Message";
"Business.Intro.IntroSticker" = "Choose Sticker";
"Business.Intro.IntroStickerValueRandom" = "Random";
"Business.Intro.CustomizeSectionHeader" = "CUSTOMIZE YOUR INTRO";
"Business.Intro.CustomizeSectionFooter" = "You can customize the message people see before they start a chat with you.";
"Business.Intro.ResetToDefault" = "Reset to Default";
"ChatbotSetup.Recipients.AddUsers" = "Add Users";
"ChatbotSetup.Recipients.RemoveAll" = "Remove All Exceptions";
"ChatbotSetup.Recipients.SelectionTitle" = "Add Exception";
"ChatbotSetup.Recipients.ExcludedListTitle" = "Excluded Chats";
"ChatbotSetup.Recipients.IncludedListTitle" = "Included Chats";
"ChatbotSetup.ErrorBotNotBusinessCapable" = "This bot doesn't support Telegram Business yet.";
"ChatbotSetup.RecipientSummary.ValueEmpty" = "Add";
"ChatbotSetup.RecipientSummary.ValueItems_1" = "1 item";
"ChatbotSetup.RecipientSummary.ValueItems_any" = "%d items";
"ChatbotSetup.RecipientSummary.ExcludedChatsItem" = "Excluded Chats";
"ChatbotSetup.RecipientSummary.IncludedChatsItem" = "Included Chats";
"Chat.ToastPhoneNumberCopied" = "Phone number copied to clipboard.";
"Chat.SpeedLimitAlert.Download.Title" = "Download speed limited";
"Chat.SpeedLimitAlert.Download.Text" = "Subscribe to [Telegram Premium]() and increase download speeds %@ times.";
"Chat.SpeedLimitAlert.Upload.Title" = "Upload speed limited";
"Chat.SpeedLimitAlert.Upload.Text" = "Subscribe to [Telegram Premium]() and increase upload speeds %@ times.";
"Chat.BusinessBotMessageTooltip" = "Only you can see that this\nmessage was sent by the bot.";
"Chat.BusinessBotPanel.ActionStart" = "START";
"Chat.BusinessBotPanel.ActionStop" = "STOP";
"Chat.BusinessBotPanel.StatusPaused" = "bot paused";
"Chat.BusinessBotPanel.StatusManages" = "bot manages this chat";
"Chat.BusinessBotPanel.StatusHasAccess" = "bot has access to this chat";
"Chat.BusinessBotPanel.Menu.RemoveBot" = "Remove bot from this chat";
"Chat.BusinessBotPanel.Menu.ManageBot" = "Manage Bot";
"Chat.Placeholder.BusinessLinkPreset" = "Add a preset message...";
"BusinessLink.ErrorExpired" = "Link Expired";
"WebApp.AlertBiometryAccessText" = "Do you want to allow %@ to use Face ID?";

View File

@ -267,10 +267,9 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
case let .secretChatLinkPreviewsInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case .botList:
//TODO:localize
return ItemListDisclosureItem(
presentationData: presentationData,
title: "Bot Settings",
title: presentationData.strings.Settings_BotListSettings,
label: "",
sectionId: self.section,
style: .blocks,

View File

@ -414,7 +414,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
arguments.openGroupsPrivacy()
})
case .groupPrivacyFooter:
return ItemListTextItem(presentationData: presentationData, text: .markdown("You can restrict which users are allowed to add you to groups and channels."), sectionId: self.section)
return ItemListTextItem(presentationData: presentationData, text: .markdown(presentationData.strings.PrivacySettings_InviteSectionFooter), sectionId: self.section)
case let .voiceMessagePrivacy(theme, text, value, hasPremium):
return ItemListDisclosureItem(presentationData: presentationData, title: text, titleIcon: hasPremium ? PresentationResourcesItemList.premiumIcon(theme) : nil, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, action: {
arguments.openVoiceMessagePrivacy()
@ -509,17 +509,16 @@ private func stringForSelectiveSettings(strings: PresentationStrings, settings:
return strings.PrivacySettings_LastSeenNobody
} else {
if enableForCloseFriends && enableForPremium {
//TODO:localize
if enableFor.isEmpty {
return "Close Friends, Premium"
return strings.PrivacySettings_ValueCloseFriendsAndPremium
} else {
return "Close Friends, Premium +\(countForSelectivePeers(enableFor))"
return strings.PrivacySettings_ValueCloseFriendsAndPremiumPlus("\(countForSelectivePeers(enableFor))").string
}
} else if enableForPremium {
if enableFor.isEmpty {
return "Premium Users"
return strings.PrivacySettings_ValuePremium
} else {
return "Premium Users +\(countForSelectivePeers(enableFor))"
return strings.PrivacySettings_ValuePremiumPlus("\(countForSelectivePeers(enableFor))").string
}
} else if enableForCloseFriends {
if enableFor.isEmpty {
@ -543,16 +542,7 @@ private func stringForSelectiveSettings(strings: PresentationStrings, settings:
}
case let .enableContacts(enableFor, disableFor, enableForPremium):
if enableForPremium {
return "Premium & Contacts"
/*if !enableFor.isEmpty && !disableFor.isEmpty {
return "Premium, " + strings.PrivacySettings_LastSeenContactsMinusPlus("\(countForSelectivePeers(disableFor))", "\(countForSelectivePeers(enableFor))").string
} else if !enableFor.isEmpty {
return "Premium, " + strings.PrivacySettings_LastSeenContactsPlus("\(countForSelectivePeers(enableFor))").string
} else if !disableFor.isEmpty {
return "Premium, " + strings.PrivacySettings_LastSeenContactsMinus("\(countForSelectivePeers(disableFor))").string
} else {
return "Premium, " + strings.PrivacySettings_LastSeenContacts
}*/
return strings.PrivacySettings_ValuePremiumAndContacts
} else {
if !enableFor.isEmpty && !disableFor.isEmpty {
return strings.PrivacySettings_LastSeenContactsMinusPlus("\(countForSelectivePeers(disableFor))", "\(countForSelectivePeers(enableFor))").string
@ -649,8 +639,7 @@ private func privacyAndSecurityControllerEntries(
entries.append(.voiceMessagePrivacy(presentationData.theme, presentationData.strings.Privacy_VoiceMessages, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.voiceMessages), isPremium))
entries.append(.messagePrivacy(presentationData.theme, privacySettings.globalSettings.nonContactChatsRequirePremium, isPremium))
}
//TODO:localize
entries.append(.groupPrivacy(presentationData.theme, "Invites", stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.groupInvitations)))
entries.append(.groupPrivacy(presentationData.theme, presentationData.strings.PrivacySettings_InviteItem, stringForSelectiveSettings(strings: presentationData.strings, settings: privacySettings.groupInvitations)))
entries.append(.groupPrivacyFooter)
} else {
entries.append(.phoneNumberPrivacy(presentationData.theme, presentationData.strings.PrivacySettings_PhoneNumber, presentationData.strings.Channel_NotificationLoading))

View File

@ -106,11 +106,10 @@ private func stringForUserCount(_ peers: [EnginePeer.Id: SelectivePrivacyPeer],
}
if enableForPremium {
//TODO:localize
if result == 0 {
return "Premium Users"
return strings.PrivacySettings_ValuePremium
} else {
return "Premium Users +\(result)"
return strings.PrivacySettings_ValuePremiumPlus("\(result)").string
}
} else {
return strings.UserCount(Int32(result))
@ -1117,7 +1116,6 @@ public func selectivePrivacySettingsController(
break
}
//TODO:localize
var additionalCategories: [ChatListNodeAdditionalCategory] = []
var selectedCategories = Set<Int>()
@ -1127,16 +1125,16 @@ public func selectivePrivacySettingsController(
id: AdditionalCategoryId.premiumUsers.rawValue,
icon: generatePremiumCategoryIcon(size: CGSize(width: 40.0, height: 40.0), cornerRadius: 12.0),
smallIcon: generatePremiumCategoryIcon(size: CGSize(width: 22.0, height: 22.0), cornerRadius: 6.0),
title: "Premium Users",
appearance: .option(sectionTitle: "USER TYPES")
title: strings.PrivacySettings_CategoryPremiumUsers,
appearance: .option(sectionTitle: strings.PrivacySettings_SearchUserTypesHeader)
)
]
selectedCategories.insert(AdditionalCategoryId.premiumUsers.rawValue)
}
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(ContactMultiselectionControllerMode.ChatSelection(
title: "Add Users",
searchPlaceholder: "Search users and groups",
title: strings.PrivacySettings_SearchUsersTitle,
searchPlaceholder: strings.PrivacySettings_SearchUsersPlaceholder,
selectedChats: Set(),
additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories),
chatListFilters: nil,

View File

@ -174,9 +174,8 @@ private enum SelectivePrivacyPeersEntry: ItemListNodeEntry {
let arguments = arguments as! SelectivePrivacyPeersControllerArguments
switch self {
case let .premiumUsersItem(editing, enabled):
//TODO:localize
let peer: EnginePeer = .user(TelegramUser(
id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(1)), accessHash: nil, firstName: "Premium Users", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil))
id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(1)), accessHash: nil, firstName: presentationData.strings.PrivacySettings_CategoryPremiumUsers, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil))
return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, customAvatarIcon: premiumAvatarIcon, presence: nil, text: .none, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: {
}, setPeerIdWithRevealedOptions: { previousId, id in
arguments.setPeerIdWithRevealedOptions(previousId, id)
@ -327,7 +326,8 @@ public func selectivePrivacyPeersController(context: AccountContext, title: Stri
case premiumUsers
}
//TODO:localize
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var additionalCategories: [ChatListNodeAdditionalCategory] = []
if displayPremiumCategory {
@ -336,8 +336,8 @@ public func selectivePrivacyPeersController(context: AccountContext, title: Stri
id: AdditionalCategoryId.premiumUsers.rawValue,
icon: generatePremiumCategoryIcon(size: CGSize(width: 40.0, height: 40.0), cornerRadius: 12.0),
smallIcon: generatePremiumCategoryIcon(size: CGSize(width: 22.0, height: 22.0), cornerRadius: 6.0),
title: "Premium Users",
appearance: .option(sectionTitle: "USER TYPES")
title: presentationData.strings.PrivacySettings_CategoryPremiumUsers,
appearance: .option(sectionTitle: presentationData.strings.PrivacySettings_SearchUserTypesHeader)
)
]
}
@ -347,8 +347,8 @@ public func selectivePrivacyPeersController(context: AccountContext, title: Stri
}
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(ContactMultiselectionControllerMode.ChatSelection(
title: "Add Users",
searchPlaceholder: "Search users and groups",
title: presentationData.strings.PrivacySettings_SearchUsersTitle,
searchPlaceholder: presentationData.strings.PrivacySettings_SearchUsersPlaceholder,
selectedChats: Set(),
additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories),
chatListFilters: nil,

View File

@ -824,13 +824,12 @@ private final class ChatEmptyNodeCloudChatContent: ASDisplayNode, ChatEmptyNodeC
]
}
case let .businessLinkSetup(link):
//TODO:localize
iconName = "Chat/Empty Chat/BusinessLink"
centerText = true
titleString = "Link to Chat"
titleString = interfaceState.strings.Business_Links_PreviewTitle
textFontSize = 13.0
strings = [
"Add a message that will be entered in the message input field for anyone who starts a chat with you using this link:"
interfaceState.strings.Business_Links_PreviewText
]
if link.url.hasPrefix("https://") {
businessLink = String(link.url[link.url.index(link.url.startIndex, offsetBy: "https://".count)...])
@ -965,7 +964,6 @@ private final class ChatEmptyNodeCloudChatContent: ASDisplayNode, ChatEmptyNodeC
var linkTextLayout: TextNodeLayout?
if let linkTextNode {
//TODO:localize
let linkTextLayoutValue = linkTextNode.updateLayoutFullInfo(CGSize(width: maxWidth - insets.left - insets.right - 10.0, height: CGFloat.greatestFiniteMagnitude))
linkTextLayout = linkTextLayoutValue
contentHeight += businessLinkTextSpacing + linkTextLayoutValue.size.height + 20.0
@ -1518,10 +1516,9 @@ private final class EmptyAttachedDescriptionNode: HighlightTrackingButtonNode {
private func updateInternal(params: Params, wallpaperBackgroundNode: WallpaperBackgroundNode?) -> CGSize {
let serviceColor = serviceMessageColorComponents(theme: params.theme, wallpaper: params.chatWallpaper)
//TODO:localize
let textString = NSMutableAttributedString()
textString.append(NSAttributedString(string: "\(params.peer.compactDisplayTitle) added the message above for all empty chats", font: Font.regular(13.0), textColor: serviceColor.primaryText))
textString.append(NSAttributedString(string: " .how?", font: Font.regular(11.0), textColor: .clear))
textString.append(NSAttributedString(string: params.strings.Chat_EmptyStateIntroFooter(params.peer.compactDisplayTitle).string, font: Font.regular(13.0), textColor: serviceColor.primaryText))
textString.append(NSAttributedString(string: " .\(params.strings.Chat_EmptyStateIntroFooterAction)", font: Font.regular(11.0), textColor: .clear))
self.textNode.attributedText = textString
let maxTextSize = CGSize(width: min(300.0, params.constrainedSize.width - 8.0 * 2.0), height: params.constrainedSize.height - 8.0 * 2.0)
@ -1597,8 +1594,7 @@ private final class EmptyAttachedDescriptionNode: HighlightTrackingButtonNode {
let textFrame = CGRect(origin: CGPoint(x: 4.0, y: 4.0), size: textLayout.size)
self.textNode.frame = textFrame
//TODO:localize
self.badgeTextNode.attributedText = NSAttributedString(string: "how?", font: Font.regular(11.0), textColor: serviceColor.primaryText)
self.badgeTextNode.attributedText = NSAttributedString(string: params.strings.Chat_EmptyStateIntroFooterAction, font: Font.regular(11.0), textColor: serviceColor.primaryText)
let badgeTextSize = self.badgeTextNode.updateLayout(CGSize(width: 200.0, height: 100.0))
if let lastLineFrame = labelRects.last {
let badgeTextFrame = CGRect(origin: CGPoint(x: lastLineFrame.maxX - badgeTextSize.width - 3.0, y: textFrame.maxY - badgeTextSize.height - 3.0 - UIScreenPixel), size: badgeTextSize)
@ -1817,7 +1813,6 @@ public final class ChatEmptyNode: ASDisplayNode {
let presentationData = self.context.sharedContext.currentPresentationData.with({ $0 })
//TODO:localize
let controller = UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.GroupInfo_InviteLink_CopyAlert_Success), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { _ in
return false
})
@ -1873,16 +1868,17 @@ public final class ChatEmptyNode: ASDisplayNode {
self.attachedDescriptionNode = attachedDescriptionNode
self.addSubnode(attachedDescriptionNode)
let strings = interfaceState.strings
attachedDescriptionNode.action = { [weak self] in
guard let self else {
return
}
//TODO:localize
let context = self.context
var replaceImpl: ((ViewController) -> Void)?
var dismissImpl: (() -> Void)?
let controller = PremiumLimitsListScreen(context: context, subject: .business, source: .other, order: [.business], buttonText: "OK", isPremium: false, forceDark: false)
let controller = PremiumLimitsListScreen(context: context, subject: .business, source: .other, order: [.business], buttonText: strings.Chat_EmptyStateIntroFooterPremiumActionButton, isPremium: false, forceDark: false)
controller.action = {
if isPremium {
dismissImpl?()

View File

@ -1112,13 +1112,12 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
displayPersonalChannel = true
}
if displayPersonalChannel {
//TODO:localize
var personalChannelTitle: String?
if let personalChannel = data.personalChannel {
personalChannelTitle = personalChannel.peer.compactDisplayTitle
}
items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerPersonalChannel, label: .text(personalChannelTitle ?? "Add"), text: "Channel", icon: nil, action: {
items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerPersonalChannel, label: .text(personalChannelTitle ?? presentationData.strings.Settings_PersonalChannelItem), text: presentationData.strings.Settings_PersonalChannelEmptyValue, icon: nil, action: {
interaction.editingOpenPersonalChannel()
}))
}
@ -1194,8 +1193,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
if let subscriberCount = personalChannel.subscriberCount {
label = presentationData.strings.Conversation_StatusSubscribers(Int32(subscriberCount))
}
//TODO:localize
items[.personalChannel]?.append(PeerInfoScreenHeaderItem(id: 0, text: "CHANNEL", label: label))
items[.personalChannel]?.append(PeerInfoScreenHeaderItem(id: 0, text: presentationData.strings.Profile_PersonalChannelSectionTitle, label: label))
items[.personalChannel]?.append(PeerInfoScreenPersonalChannelItem(id: 1, context: context, data: personalChannel, controller: { [weak interaction] in
guard let interaction else {
return nil
@ -7712,18 +7710,17 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
return
}
//TODO:localize
let toastText: String
var mappedChannel: TelegramPersonalChannel?
if let channel {
mappedChannel = TelegramPersonalChannel(peerId: channel.peer.id, subscriberCount: channel.subscriberCount.flatMap(Int32.init(clamping:)), topMessageId: nil)
if initialData.channelId != nil {
toastText = "Personal channel updated."
toastText = self.presentationData.strings.Settings_PersonalChannelUpdatedToast
} else {
toastText = "Personal channel added."
toastText = self.presentationData.strings.Settings_PersonalChannelAddedToast
}
} else {
toastText = "Personal channel removed."
toastText = self.presentationData.strings.Settings_PersonalChannelRemovedToast
}
let _ = self.context.engine.accountData.updatePersonalChannel(personalChannel: mappedChannel).startStandalone()

View File

@ -16,6 +16,7 @@ import Markdown
import UndoUI
import AnimatedAvatarSetNode
import AvatarNode
import TelegramStringFormatting
private final class SendInviteLinkScreenComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@ -390,11 +391,10 @@ private final class SendInviteLinkScreenComponent: Component {
self.premiumButton = premiumButton
}
//TODO:localize
let premiumTitleSize = premiumTitle.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "Upgrade to Premium", font: Font.semibold(24.0), textColor: environment.theme.list.itemPrimaryTextColor))
text: .plain(NSAttributedString(string: environment.strings.SendInviteLink_TitleUpgradeToPremium, font: Font.semibold(24.0), textColor: environment.theme.list.itemPrimaryTextColor))
)),
environment: {},
containerSize: CGSize(width: availableSize.width - leftButtonFrame.maxX * 2.0, height: 100.0)
@ -410,33 +410,38 @@ private final class SendInviteLinkScreenComponent: Component {
contentHeight += premiumTitleSize.height
contentHeight += 8.0
//TODO:localize
let text: String
if premiumRestrictedUsers.count == 1 {
text = "**\(premiumRestrictedUsers[0].peer.compactDisplayTitle)** accepts invitations to groups from contacts and **Premium** users."
text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(premiumRestrictedUsers[0].peer.compactDisplayTitle).string
} else {
let extraCount = premiumRestrictedUsers.count - 3
var peersText = ""
var peersTextArray: [String] = []
for i in 0 ..< min(3, premiumRestrictedUsers.count) {
if extraCount == 0 && i == premiumRestrictedUsers.count - 1 {
peersText.append(", and ")
} else if i != 0 {
peersText.append(", ")
peersTextArray.append("**\(premiumRestrictedUsers[i].peer.compactDisplayTitle)**")
}
var peersText = ""
if #available(iOS 13.0, *) {
let listFormatter = ListFormatter()
listFormatter.locale = localeWithStrings(environment.strings)
if let value = listFormatter.string(from: peersTextArray) {
peersText = value
}
}
if peersText.isEmpty {
for i in 0 ..< peersTextArray.count {
if i != 0 {
peersText.append(", ")
}
peersText.append(peersTextArray[i])
}
peersText.append("**")
peersText.append(premiumRestrictedUsers[i].peer.compactDisplayTitle)
peersText.append("**")
}
if extraCount >= 1 {
if extraCount == 1 {
text = "\(peersText), and **\(extraCount)** more person only accept invitations to groups from contacts and **Premium** users."
} else {
text = "\(peersText), and **\(extraCount)** more people only accept invitations to groups from contacts and **Premium** users."
}
text = environment.strings.SendInviteLink_TextContactsAndPremiumMultipleUsers(Int32(extraCount)).replacingOccurrences(of: "{user_list}", with: peersText)
} else {
text = "\(peersText) only accept invitations to groups from contacts and **Premium** users."
text = environment.strings.SendInviteLink_TextContactsAndPremiumOneUser(peersText).string
}
}
@ -469,7 +474,7 @@ private final class SendInviteLinkScreenComponent: Component {
contentHeight += premiumTextSize.height
contentHeight += 22.0
let premiumButtonTitle = "Subscribe to Telegram Premium"
let premiumButtonTitle = environment.strings.SendInviteLink_SubscribeToPremiumButton
let premiumButtonSize = premiumButton.update(
transition: transition,
component: AnyComponent(SolidRoundedButtonComponent(
@ -502,7 +507,6 @@ private final class SendInviteLinkScreenComponent: Component {
controller.dismiss()
//TODO:localize
let premiumController = component.context.sharedContext.makePremiumIntroController(context: component.context, source: .settings, forceDark: false, dismissed: nil)
navigationController?.pushViewController(premiumController)
}
@ -555,7 +559,7 @@ private final class SendInviteLinkScreenComponent: Component {
let premiumSeparatorTextSize = premiumSeparatorText.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "or", font: Font.regular(15.0), textColor: environment.theme.list.itemSecondaryTextColor))
text: .plain(NSAttributedString(string: environment.strings.SendInviteLink_PremiumOrSendSectionSeparator, font: Font.regular(15.0), textColor: environment.theme.list.itemSecondaryTextColor))
)),
environment: {},
containerSize: CGSize(width: availableSize.width - leftButtonFrame.maxX * 2.0, height: 100.0)
@ -658,8 +662,7 @@ private final class SendInviteLinkScreenComponent: Component {
let text: String
if !premiumRestrictedUsers.isEmpty {
if component.link != nil {
//TODO:localize
text = "You can try to send an invite link instead."
text = environment.strings.SendInviteLink_TextSendInviteLink
} else {
if component.peers.count == 1 {
text = environment.strings.SendInviteLink_TextUnavailableSingleUser(component.peers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast)).string
@ -738,8 +741,7 @@ private final class SendInviteLinkScreenComponent: Component {
let itemSubtitle: PeerListItemComponent.Subtitle
let canBeSelected = component.link != nil && !peer.premiumRequiredToContact
if peer.premiumRequiredToContact {
//TODO:localize
itemSubtitle = .text(text: "Available only to premium users", icon: .lock)
itemSubtitle = .text(text: environment.strings.SendInviteLink_StatusAvailableToPremiumOnly, icon: .lock)
} else {
itemSubtitle = .presence(component.peerPresences[peer.peer.id])
}

View File

@ -135,13 +135,11 @@ final class BusinessLinkListItemComponent: Component {
let titleViewCountSpacing: CGFloat = 4.0
let titleTextSpacing: CGFloat = 4.0
//TODO:localize
let viewCountText: String
if component.link.viewCount == 0 {
viewCountText = "no clicks"
viewCountText = component.strings.Business_Links_ItemNoClicks
} else {
viewCountText = "\(component.link.viewCount) clicks"
viewCountText = component.strings.Business_Links_ItemClickCount(Int32(component.link.viewCount))
}
let viewCountSize = self.viewCount.update(
transition: .immediate,
@ -191,7 +189,7 @@ final class BusinessLinkListItemComponent: Component {
}
}
let textString = stringWithAppliedEntities(
component.link.message.isEmpty ? "No text" : component.link.message,
component.link.message.isEmpty ? component.strings.Business_Links_ItemNoText : component.link.message,
entities: filteredEntities,
baseColor: component.theme.list.itemSecondaryTextColor,
linkColor: component.theme.list.itemSecondaryTextColor,
@ -252,11 +250,10 @@ final class BusinessLinkListItemComponent: Component {
self.swipeOptionContainer.updateLayout(size: swipeOptionContainerFrame.size, leftInset: 0.0, rightInset: 0.0)
var rightOptions: [ListItemSwipeOptionContainer.Option] = []
//TODO:localize
rightOptions = [
ListItemSwipeOptionContainer.Option(
key: 0,
title: "Share",
title: component.strings.Business_Links_ItemActionShare,
icon: .none,
color: component.theme.list.itemDisclosureActions.accent.fillColor,
textColor: component.theme.list.itemDisclosureActions.accent.foregroundColor

View File

@ -181,7 +181,7 @@ final class BusinessLinksSetupScreenComponent: Component {
case .generic:
errorText = presentationData.strings.Login_UnknownError
case .tooManyLinks:
errorText = "You can't create more links"
errorText = presentationData.strings.Business_Links_ErrorTooManyLinks
}
environment.controller()?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: errorText, actions: [
@ -229,7 +229,7 @@ final class BusinessLinksSetupScreenComponent: Component {
let actionSheet = ActionSheetController(presentationData: presentationData)
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: "Delete Link", color: .destructive, action: { [weak self, weak actionSheet] in
ActionSheetButtonItem(title: presentationData.strings.Business_Links_DeleteItemConfirmationAction, color: .destructive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated()
guard let self, let component = self.component else {
@ -308,11 +308,10 @@ final class BusinessLinksSetupScreenComponent: Component {
let _ = alphaTransition
let _ = presentationData
//TODO:localize
let navigationTitleSize = self.navigationTitle.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "Links to Chat", font: Font.semibold(17.0), textColor: environment.theme.rootController.navigationBar.primaryTextColor)),
text: .plain(NSAttributedString(string: environment.strings.Business_Links, font: Font.semibold(17.0), textColor: environment.theme.rootController.navigationBar.primaryTextColor)),
horizontalAlignment: .center
)),
environment: {},
@ -359,7 +358,7 @@ final class BusinessLinksSetupScreenComponent: Component {
contentHeight += 129.0
let subtitleString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString("Give your customers short links that start a chat with you — and suggest the first message from them to you.", attributes: MarkdownAttributes(
let subtitleString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Business_Links_Text, attributes: MarkdownAttributes(
body: MarkdownAttributeSet(font: Font.regular(15.0), textColor: environment.theme.list.freeTextColor),
bold: MarkdownAttributeSet(font: Font.semibold(15.0), textColor: environment.theme.list.freeTextColor),
link: MarkdownAttributeSet(font: Font.regular(15.0), textColor: environment.theme.list.itemAccentColor),
@ -406,7 +405,7 @@ final class BusinessLinksSetupScreenComponent: Component {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Create a Link to Chat",
string: environment.strings.Business_Links_CreateAction,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemAccentColor
)),
@ -428,11 +427,11 @@ final class BusinessLinksSetupScreenComponent: Component {
let footerText: String
if let addressName = component.initialData.accountPeer?.addressName, let phoneNumber = component.initialData.accountPeer?.phone {
footerText = "You can also use a simple link for a chat with you — [t.me/\(addressName)](username) or [t.me/\u{2060}+\u{2060}\(phoneNumber)](phone)."
footerText = environment.strings.Business_Links_SimpleLinkInfoUsernamePhone(addressName, phoneNumber).string
} else if let addressName = component.initialData.accountPeer?.addressName {
footerText = "You can also use a simple link for a chat with you — [t.me/\(addressName)](username)."
footerText = environment.strings.Business_Links_SimpleLinkInfoUsername(addressName).string
} else if let phoneNumber = component.initialData.accountPeer?.phone {
footerText = "You can also use a simple link for a chat with you — [t.me/\u{2060}+\u{2060}\(phoneNumber)](phone)."
footerText = environment.strings.Business_Links_SimpleLinkInfoPhone(phoneNumber).string
} else {
footerText = ""
}
@ -490,7 +489,6 @@ final class BusinessLinksSetupScreenComponent: Component {
return true
}
}
//TODO:localize
let controller = UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.GroupInfo_InviteLink_CopyAlert_Success), elevatedLayout: false, position: .bottom, animateInAsReplacement: animateAsReplacement, action: { _ in
return false
})
@ -546,7 +544,7 @@ final class BusinessLinksSetupScreenComponent: Component {
theme: environment.theme,
header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "LINKS TO CHAT",
string: environment.strings.Business_Links_LinksSectionHeader,
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
textColor: environment.theme.list.freeTextColor
)),

View File

@ -153,8 +153,7 @@ public func botListSettingsScreen(context: AccountContext) -> ViewController {
)
|> deliverOnMainQueue
|> map { presentationData, state, botPeerList -> (ItemListControllerState, (ItemListNodeState, Any)) in
//TODO:localize
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Bots"), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Settings_BotListSettings), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botListSettingsEntries(presentationData: presentationData, peers: botPeerList), style: .blocks, animateChanges: true)
return (controllerState, (listState, arguments))

View File

@ -59,10 +59,9 @@ private enum BotSettingsEntry: ItemListNodeEntry {
let arguments = arguments as! BotSettingsArguments
switch self {
case let .biometryAccess(value):
//TODO:localize
return ItemListSwitchItem(
presentationData: presentationData,
title: "Biometry",
title: presentationData.strings.Settings_BotSettings_Biometry,
value: value,
sectionId: self.section,
style: .blocks,
@ -133,7 +132,6 @@ public func botSettingsScreen(context: AccountContext, peerId: EnginePeer.Id) ->
|> map { presentationData, state, data -> (ItemListControllerState, (ItemListNodeState, Any)) in
let (peer, biometricsState) = data
//TODO:localize
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(peer?.compactDisplayTitle ?? ""), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botSettingsEntries(presentationData: presentationData, peer: peer, biometricsState: biometricsState), style: .blocks, animateChanges: true)

View File

@ -306,71 +306,6 @@ final class BusinessIntroSetupScreenComponent: Component {
self.state?.updated(transition: .immediate)
} else {
let context = component.context
/*let localSets = context.engine.stickers.searchStickerSets(query: query)
let remoteSets: Signal<FoundStickerSets?, NoError> = .single(nil) |> then(
context.engine.stickers.searchStickerSetsRemotely(query: query)
|> map(Optional.init)
)
let resultSignal = combineLatest(
localSets,
remoteSets
)
|> mapToSignal { localSets, remoteSets -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
if localSets.infos.isEmpty && remoteSets == nil {
return .complete()
}
var items: [EmojiPagerContentComponent.Item] = []
var mergedSets = localSets
if let remoteSets {
mergedSets = mergedSets.merge(with: remoteSets)
}
var existingIds = Set<MediaId>()
for entry in mergedSets.entries {
guard let stickerPackItem = entry.item as? StickerPackItem else {
continue
}
let itemFile = stickerPackItem.file
if existingIds.contains(itemFile.fileId) {
continue
}
existingIds.insert(itemFile.fileId)
let animationData = EntityKeyboardAnimationData(file: itemFile)
let item = EmojiPagerContentComponent.Item(
animationData: animationData,
content: .animation(animationData),
itemFile: itemFile,
subgroupId: nil,
icon: .none,
tintMode: animationData.isTemplate ? .primary : .none
)
items.append(item)
}
return .single([EmojiPagerContentComponent.ItemGroup(
supergroupId: "search",
groupId: "search",
title: nil,
subtitle: nil,
badge: nil,
actionButtonTitle: nil,
isFeatured: false,
isPremiumLocked: false,
isEmbedded: false,
hasClear: false,
hasEdit: false,
collapsedLineCount: nil,
displayPremiumBadges: false,
headerItem: nil,
fillWithLoadingPlaceholders: false,
items: items
)])
}*/
let stickers: Signal<[(String?, FoundStickerItem)], NoError> = Signal { subscriber in
var signals: Signal<[Signal<(String?, [FoundStickerItem]), NoError>], NoError> = .single([])
@ -711,11 +646,10 @@ final class BusinessIntroSetupScreenComponent: Component {
let _ = alphaTransition
let _ = presentationData
//TODO:localize
let navigationTitleSize = self.navigationTitle.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "Intro", font: Font.semibold(17.0), textColor: environment.theme.rootController.navigationBar.primaryTextColor)),
text: .plain(NSAttributedString(string: environment.strings.Business_Intro_Title, font: Font.semibold(17.0), textColor: environment.theme.rootController.navigationBar.primaryTextColor)),
horizontalAlignment: .center
)),
environment: {},
@ -765,7 +699,7 @@ final class BusinessIntroSetupScreenComponent: Component {
resetText: self.resetTitle.flatMap {
return ListMultilineTextFieldItemComponent.ResetText(value: $0)
},
placeholder: "Enter Title",
placeholder: environment.strings.Business_Intro_IntroTitlePlaceholder,
autocapitalizationType: .none,
autocorrectionType: .no,
returnKeyType: .next,
@ -796,7 +730,7 @@ final class BusinessIntroSetupScreenComponent: Component {
resetText: self.resetText.flatMap {
return ListMultilineTextFieldItemComponent.ResetText(value: $0)
},
placeholder: "Enter Message",
placeholder: environment.strings.Business_Intro_IntroTextPlaceholder,
autocapitalizationType: .none,
autocorrectionType: .no,
returnKeyType: .done,
@ -829,7 +763,7 @@ final class BusinessIntroSetupScreenComponent: Component {
} else {
stickerIcon = ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Random",
string: environment.strings.Business_Intro_IntroStickerValueRandom,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemSecondaryTextColor
)),
@ -842,7 +776,7 @@ final class BusinessIntroSetupScreenComponent: Component {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Choose Sticker",
string: environment.strings.Business_Intro_IntroSticker,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemPrimaryTextColor
)),
@ -870,7 +804,7 @@ final class BusinessIntroSetupScreenComponent: Component {
theme: environment.theme,
header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "CUSTOMIZE YOUR INTRO",
string: environment.strings.Business_Intro_CustomizeSectionHeader,
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
textColor: environment.theme.list.freeTextColor
)),
@ -878,7 +812,7 @@ final class BusinessIntroSetupScreenComponent: Component {
)),
footer: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "You can customize the message people see before they start a chat with you.",
string: environment.strings.Business_Intro_CustomizeSectionFooter,
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
textColor: environment.theme.list.freeTextColor
)),
@ -903,14 +837,14 @@ final class BusinessIntroSetupScreenComponent: Component {
let titleText: String
if self.titleInputState.text.string.isEmpty {
titleText = "No messages here yet..."
titleText = environment.strings.Conversation_EmptyPlaceholder
} else {
titleText = self.titleInputState.text.string
}
let textText: String
if self.textInputState.text.string.isEmpty {
textText = "Send a message or tap on the greeting below"
textText = environment.strings.Conversation_GreetingText
} else {
textText = self.textInputState.text.string
}
@ -962,7 +896,7 @@ final class BusinessIntroSetupScreenComponent: Component {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Reset to Default",
string: environment.strings.Business_Intro_ResetToDefault,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemDestructiveColor
)),
@ -1040,7 +974,7 @@ final class BusinessIntroSetupScreenComponent: Component {
var stickerSearchResults: EmojiPagerContentComponent.EmptySearchResults?
if !stickerSearchResult.groups.contains(where: { !$0.items.isEmpty || $0.fillWithLoadingPlaceholders }) {
stickerSearchResults = EmojiPagerContentComponent.EmptySearchResults(
text: "No stickers found",
text: environment.strings.Stickers_NoStickersFound,
iconFile: nil
)
}

View File

@ -238,8 +238,7 @@ public final class BusinessLinkNameAlertContentNode: AlertContentNode {
self.subtext = subtext
self.titleFont = titleFont
//TODO:localize
self.inputFieldNode = PromptInputFieldNode(theme: ptheme, placeholder: "Name this link...", characterLimit: characterLimit)
self.inputFieldNode = PromptInputFieldNode(theme: ptheme, placeholder: strings.Business_Links_LinkNameInputPlaceholder, characterLimit: characterLimit)
self.inputFieldNode.text = value ?? ""
self.actionNodesSeparator = ASDisplayNode()

View File

@ -235,9 +235,8 @@ final class BusinessRecipientListScreenComponent: Component {
}
}
//TODO:localize
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(ContactMultiselectionControllerMode.ChatSelection(
title: "Add Exception",
title: presentationData.strings.ChatbotSetup_Recipients_SelectionTitle,
searchPlaceholder: presentationData.strings.ChatListFilter_AddChatsSearchPlaceholder,
selectedChats: Set(initialPeerList.peers.map(\.peer.id)),
additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories),
@ -377,12 +376,11 @@ final class BusinessRecipientListScreenComponent: Component {
let title: String
switch component.mode {
case .excludeExceptions, .excludeUsers:
title = "Excluded Chats"
title = environment.strings.ChatbotSetup_Recipients_ExcludedListTitle
case .includeExceptions:
title = "Included Chats"
title = environment.strings.ChatbotSetup_Recipients_IncludedListTitle
}
//TODO:localize
let navigationTitleSize = self.navigationTitle.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(
@ -417,7 +415,7 @@ final class BusinessRecipientListScreenComponent: Component {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Add Users",
string: environment.strings.ChatbotSetup_Recipients_AddUsers,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemAccentColor
)),
@ -570,7 +568,7 @@ final class BusinessRecipientListScreenComponent: Component {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Remove All Exceptions",
string: environment.strings.ChatbotSetup_Recipients_RemoveAll,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemDestructiveColor
)),

View File

@ -689,8 +689,7 @@ final class ChatbotSetupScreenComponent: Component {
self.botResolutionState = botResolutionState
self.state?.updated(transition: .spring(duration: 0.3))
} else {
//TODO:localize
self.environment?.controller()?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: "This bot doesn't support Telegram Business yet.", actions: [
self.environment?.controller()?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.ChatbotSetup_ErrorBotNotBusinessCapable, actions: [
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
})
]), in: .window(.root))
@ -834,25 +833,20 @@ final class ChatbotSetupScreenComponent: Component {
contentHeight += accessSectionSize.height
contentHeight += sectionSpacing
//TODO:localize
let categoriesAndUsersItemCount = self.additionalPeerList.categories.count + self.additionalPeerList.peers.count
let excludedSectionValue: String
if categoriesAndUsersItemCount == 0 {
excludedSectionValue = "Add"
} else if categoriesAndUsersItemCount == 1 {
excludedSectionValue = "1 item"
excludedSectionValue = environment.strings.ChatbotSetup_RecipientSummary_ValueEmpty
} else {
excludedSectionValue = "\(categoriesAndUsersItemCount) items"
excludedSectionValue = environment.strings.ChatbotSetup_RecipientSummary_ValueItems(Int32(categoriesAndUsersItemCount))
}
let excludedUsersItemCount = self.additionalPeerList.excludePeers.count
let excludedUsersValue: String
if excludedUsersItemCount == 0 {
excludedUsersValue = "Add"
} else if excludedUsersItemCount == 1 {
excludedUsersValue = "1 item"
excludedUsersValue = environment.strings.ChatbotSetup_RecipientSummary_ValueEmpty
} else {
excludedUsersValue = "\(excludedUsersItemCount) items"
excludedUsersValue = environment.strings.ChatbotSetup_RecipientSummary_ValueItems(Int32(excludedUsersItemCount))
}
var excludedSectionItems: [AnyComponentWithIdentity<Empty>] = []
@ -861,7 +855,7 @@ final class ChatbotSetupScreenComponent: Component {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: self.hasAccessToAllChatsByDefault ? "Excluded Chats" : "Included Chats",
string: self.hasAccessToAllChatsByDefault ? environment.strings.ChatbotSetup_RecipientSummary_ExcludedChatsItem : environment.strings.ChatbotSetup_RecipientSummary_IncludedChatsItem,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemPrimaryTextColor
)),
@ -920,7 +914,6 @@ final class ChatbotSetupScreenComponent: Component {
contentHeight += excludedSectionSize.height
contentHeight += sectionSpacing
//TODO:localize
var excludedUsersContentHeight: CGFloat = 0.0
var excludedUsersSectionItems: [AnyComponentWithIdentity<Empty>] = []
excludedUsersSectionItems.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
@ -928,7 +921,7 @@ final class ChatbotSetupScreenComponent: Component {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Excluded Chats",
string: environment.strings.ChatbotSetup_RecipientSummary_ExcludedChatsItem,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemPrimaryTextColor
)),

View File

@ -523,8 +523,7 @@ private final class CollectibleItemInfoScreenContentComponent: Component {
case let .phoneNumber(phoneNumber):
let formattedPhoneNumber = formatPhoneNumber(context: component.context, number: phoneNumber.phoneNumber)
UIPasteboard.general.string = formattedPhoneNumber
//TODO:localize
toastText = "Phone number copied to clipboard."
toastText = environment.strings.Chat_ToastPhoneNumberCopied
}
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }

View File

@ -87,7 +87,7 @@ final class PeerSelectionScreenComponent: Component {
presentationData: ItemListPresentationData(listNode.presentationData),
icon: PresentationResourcesItemList.hideIconImage(listNode.presentationData.theme),
iconSignal: nil,
title: "Hide Personal Channel",
title: listNode.presentationData.strings.Settings_PersonalChannelRemove,
additionalBadgeIcon: nil,
alwaysPlain: true,
hasSeparator: true,
@ -103,12 +103,11 @@ final class PeerSelectionScreenComponent: Component {
}
)
case let .item(peer, subscriberCount, _):
//TODO:localize
let statusText: String
if let subscriberCount, subscriberCount != 0 {
statusText = "\(subscriberCount) subscribers"
statusText = listNode.presentationData.strings.Conversation_StatusSubscribers(Int32(subscriberCount))
} else {
statusText = "channel"
statusText = listNode.presentationData.strings.Channel_Status
}
return ContactsPeerItem(
@ -273,7 +272,6 @@ final class PeerSelectionScreenComponent: Component {
) -> CGFloat {
let rightButtons: [AnyComponentWithIdentity<NavigationButtonComponentEnvironment>] = []
//TODO:localize
let closeTitle: String = strings.Common_Cancel
let headerContent: ChatListHeaderComponent.Content? = ChatListHeaderComponent.Content(
@ -281,10 +279,10 @@ final class PeerSelectionScreenComponent: Component {
navigationBackTitle: nil,
titleComponent: AnyComponent(VStack([
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "Channel", font: Font.semibold(17.0), textColor: theme.rootController.navigationBar.primaryTextColor))
text: .plain(NSAttributedString(string: strings.Settings_PersonalChannelSelectTitle, font: Font.semibold(17.0), textColor: theme.rootController.navigationBar.primaryTextColor))
))),
AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "select your channel", font: Font.regular(12.0), textColor: theme.rootController.navigationBar.secondaryTextColor))
text: .plain(NSAttributedString(string: strings.Settings_PersonalChannelSelectSubtitle, font: Font.regular(12.0), textColor: theme.rootController.navigationBar.secondaryTextColor))
)))
], spacing: 2.0)),
chatListTitle: nil,

View File

@ -172,7 +172,6 @@ final class ChatBusinessLinkTitlePanelNode: ChatTitleAccessoryPanelNode {
let presentationData = self.context.sharedContext.currentPresentationData.with({ $0 })
//TODO:localize
let controller = UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.GroupInfo_InviteLink_CopyAlert_Success), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { _ in
return false
})

View File

@ -767,10 +767,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let message = inputText.string
if message != link.message || entities != link.entities {
//TODO:localize
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: "You have unsaved changes. Reset?", actions: [
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: strongSelf.presentationData.strings.Business_Links_AlertUnsavedText, actions: [
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}),
TextAlertAction(type: .destructiveAction, title: "Reset", action: { [weak strongSelf] in
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.Business_Links_AlertUnsavedAction, action: { [weak strongSelf] in
strongSelf?.dismiss()
})
]), in: .window(.root))
@ -6320,8 +6319,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
linkUrl = link.url
}
//TODO:localize
self.chatTitleView?.titleContent = .custom(link.title ?? "Link to Chat", linkUrl, false)
self.chatTitleView?.titleContent = .custom(link.title ?? self.presentationData.strings.Business_Links_EditLinkTitle, linkUrl, false)
}
} else {
self.chatTitleView?.titleContent = .custom(" ", nil, false)
@ -8485,8 +8483,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
customChatContents.businessLinkUpdate(message: text, entities: entities, title: link.title)
}
//TODO:localize
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .succeed(text: "Preset message saved.", timeout: nil, customUndoText: nil), elevatedLayout: false, action: { _ in return false }), in: .current)
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .succeed(text: strongSelf.presentationData.strings.Business_Links_EditLinkToastSaved, timeout: nil, customUndoText: nil), elevatedLayout: false, action: { _ in return false }), in: .current)
}
}
@ -11872,7 +11869,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
//TODO:localize
let title: String
let text: String
switch event {
@ -11881,15 +11877,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let data = self.context.currentAppConfiguration.with({ $0 }).data, let value = data["upload_premium_speedup_download"] as? Double {
speedIncreaseFactor = Int(value)
}
title = "Download speed limited"
text = "Subscribe to [Telegram Premium]() and increase download speeds \(speedIncreaseFactor) times."
title = self.presentationData.strings.Chat_SpeedLimitAlert_Download_Title
text = self.presentationData.strings.Chat_SpeedLimitAlert_Download_Text("\(speedIncreaseFactor)").string
case .upload:
var speedIncreaseFactor = 10
if let data = self.context.currentAppConfiguration.with({ $0 }).data, let value = data["upload_premium_speedup_upload"] as? Double {
speedIncreaseFactor = Int(value)
}
title = "Upload speed limited"
text = "Subscribe to [Telegram Premium]() and increase upload speeds \(speedIncreaseFactor) times."
title = self.presentationData.strings.Chat_SpeedLimitAlert_Upload_Title
text = self.presentationData.strings.Chat_SpeedLimitAlert_Upload_Text("\(speedIncreaseFactor)").string
}
let content: UndoOverlayContent = .universal(animation: "anim_speed_low", scale: 0.066, colors: [:], title: title, text: text, customUndoText: nil, timeout: 5.0)

View File

@ -28,8 +28,7 @@ extension ChatControllerImpl {
let bounds = statusNode.view.convert(statusNode.view.bounds, to: self.chatDisplayNode.view)
let location = CGPoint(x: bounds.midX, y: bounds.minY - 11.0)
//TODO:localize
let tooltipController = TooltipController(content: .text("Only you can see that this\nmessage was sent by the bot."), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, balancedTextLayout: true, timeout: 3.5, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
let tooltipController = TooltipController(content: .text(self.presentationData.strings.Chat_BusinessBotMessageTooltip), baseFontSize: self.presentationData.listsFontSize.baseDisplaySize, balancedTextLayout: true, timeout: 3.5, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
self.checksTooltipController = tooltipController
tooltipController.dismissed = { [weak self, weak tooltipController] _ in
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.checksTooltipController === tooltipController {

View File

@ -66,8 +66,8 @@ extension ChatControllerImpl {
var completion: ((String?) -> Void)?
let alertController = businessLinkNameAlertController(
context: self.context,
text: "Link Name",
subtext: "Add a name for this link that only you will see.",
text: self.presentationData.strings.Business_Links_LinkNameTitle,
subtext: self.presentationData.strings.Business_Links_LinkNameText,
value: currentValue,
characterLimit: 32,
apply: { value in
@ -93,8 +93,7 @@ extension ChatControllerImpl {
} else {
linkUrl = link.url
}
//TODO:localize
self.chatTitleView?.titleContent = .custom(value.isEmpty ? "Link to Chat" : value, linkUrl, false)
self.chatTitleView?.titleContent = .custom(value.isEmpty ? self.presentationData.strings.Business_Links_EditLinkTitle : value, linkUrl, false)
if case let .customChatContents(customChatContents) = self.subject {
customChatContents.businessLinkUpdate(message: link.message, entities: link.entities, title: value.isEmpty ? nil : value)
}

View File

@ -102,12 +102,11 @@ private final class ChatManagingBotTitlePanelComponent: Component {
let rightInset: CGFloat = component.insets.right + 10.0
let actionAndSettingsButtonsSpacing: CGFloat = 8.0
//TODO:localize
let actionButtonSize = self.actionButton.update(
transition: transition,
component: AnyComponent(PlainButtonComponent(
content: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: component.isPaused ? "START" : "STOP", font: Font.semibold(15.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
text: .plain(NSAttributedString(string: component.isPaused ? component.strings.Chat_BusinessBotPanel_ActionStart : component.strings.Chat_BusinessBotPanel_ActionStop, font: Font.semibold(15.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
)),
background: AnyComponent(RoundedRectangle(
color: component.theme.list.itemCheckColors.fillColor,
@ -169,12 +168,11 @@ private final class ChatManagingBotTitlePanelComponent: Component {
environment: {},
containerSize: CGSize(width: maxTextWidth, height: 100.0)
)
//TODO:localize
let textValue: String
if component.isPaused {
textValue = "bot paused"
textValue = component.strings.Chat_BusinessBotPanel_StatusPaused
} else {
textValue = component.managesChat ? "bot manages this chat" : "bot has access to this chat"
textValue = component.managesChat ? component.strings.Chat_BusinessBotPanel_StatusManages : component.strings.Chat_BusinessBotPanel_StatusHasAccess
}
let textSize = self.text.update(
transition: .immediate,
@ -292,12 +290,10 @@ final class ChatManagingBotTitlePanelNode: ChatTitleAccessoryPanelNode {
}
let strings = self.context.sharedContext.currentPresentationData.with { $0 }.strings
let _ = strings
var items: [ContextMenuItem] = []
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Remove bot from this chat", textColor: .destructive, icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.Chat_BusinessBotPanel_Menu_RemoveBot, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.destructiveColor)
}, action: { [weak self] _, a in
a(.default)
@ -308,7 +304,7 @@ final class ChatManagingBotTitlePanelNode: ChatTitleAccessoryPanelNode {
self.context.engine.peers.removeChatManagingBot(chatId: chatPeerId)
})))
if let url = managingBot.settingsUrl {
items.append(.action(ContextMenuActionItem(text: "Manage Bot", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.Chat_BusinessBotPanel_Menu_ManageBot, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Settings"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
a(.default)

View File

@ -1873,8 +1873,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
placeholder = interfaceState.strings.Chat_Placeholder_AwayMessage
}
case .businessLinkSetup:
//TODO:localize
placeholder = "Add a preset message..."
placeholder = interfaceState.strings.Chat_Placeholder_BusinessLinkPreset
}
}

View File

@ -1071,8 +1071,7 @@ func openResolvedUrlImpl(
))
}
} else {
//TODO:localize
present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: "Link expired.", actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.BusinessLink_ErrorExpired, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}
}
}

View File

@ -1498,14 +1498,13 @@ public final class WebAppController: ViewController, AttachmentContainable {
self.sendBiometryInfoReceivedEvent()
}
//TODO:localize
var alertTitle: String?
let alertText: String
if let reason {
alertTitle = "Do you want to allow \(botPeer.compactDisplayTitle) to use Face ID?"
alertTitle = self.presentationData.strings.WebApp_AlertBiometryAccessText(botPeer.compactDisplayTitle).string
alertText = reason
} else {
alertText = "Do you want to allow \(botPeer.compactDisplayTitle) to use Face ID?"
alertText = self.presentationData.strings.WebApp_AlertBiometryAccessText(botPeer.compactDisplayTitle).string
}
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: alertTitle, text: alertText, actions: [
TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_No, action: {