diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 0f35cb28f3..5546b4bb27 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -9166,3 +9166,153 @@ Sorry for the inconvenience."; "WallpaperPreview.PreviewInDayMode" = "Preview this background in day mode."; "Conversation.Theme.ApplyBackground" = "Set as Background"; + +"ChatList.ContextMuteAll" = "Mute All"; +"ChatList.ContextUnmuteAll" = "Unmute All"; +"ChatList.ToastFolderMuted" = "All chats in **%@** are now muted"; +"ChatList.ToastFolderUnmuted" = "All chats in **%@** are now unmuted"; +"ChatList.ContextMenuShare" = "Share"; +"ChatList.ContextMenuBadgeNew" = "NEW"; +"ChatList.AlertDeleteFolderTitle" = "Delete Folder"; +"ChatList.AlertDeleteFolderText" = "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder."; +"ChatList.PanelNewChatsAvailable_1" = "1 New Chat Available"; +"ChatList.PanelNewChatsAvailable_any" = "%d New Chats Available"; + +"ChatListFilter.SectionShare" = "SHARE FOLDER"; +"ChatListFilter.CreateLink" = "Create a new Link"; +"ChatListFilter.CreateLinkNew" = "Create an Invite Link"; +"ChatListFilter.ExcludeChatsAction" = "Add Chats to Exclude"; +"ChatListFilter.LinkListInfo" = "Create more links to set up different access levels for different people."; +"ChatListFilter.LinkListInfoNew" = "Share access to some of this folder's groups and channels with others."; +"ChatListFilter.ToastChatsAddedTitle_1" = "Сhat added to folder"; +"ChatListFilter.ToastChatsAddedTitle_any" = "%d chats added to folder"; +"ChatListFilter.ToastChatsAddedText" = "It will not affect chatlist of the links of this folder"; +"ChatListFilter.ToastChatsRemovedTitle_1" = "Сhat removed from folder"; +"ChatListFilter.ToastChatsRemovedTitle_any" = "%d chats added to folder"; +"ChatListFilter.ToastChatsRemovedText" = "It will not affect chatlist of the links of this folder"; +"ChatListFilter.AlertCreateFolderBeforeSharingText" = "Please finish creating this folder to share it."; +"ChatListFilter.ErrorShareInvalidFolder" = "You can’t share folders which have chat types or excluded chats."; +"ChatListFilter.SaveAlertActionSave" = "Save"; +"ChatListFilter.CreateLinkUnknownError" = "Error creating a share link"; +"ChatListFilter.CreateLinkErrorSomeoneHasChannelLimit" = "One of the groups in this folder can’t be added because one of its admins has too many groups and channels."; + +"ChatListFilterList.CreateFolder" = "Create a Folder"; + +"FolderLinkScreen.LabelCanInvite" = "you can invite others here"; + +"FolderLinkScreen.LabelUnavailableBot" = "you can't share chats with bots"; +"FolderLinkScreen.AlertTextUnavailableBot" = "You can't share chats with bots"; + +"FolderLinkScreen.LabelUnavailableUser" = "you can't share private chats"; +"FolderLinkScreen.AlertTextUnavailableUser" = "You can't share private chats"; + +"FolderLinkScreen.LabelUnavailableGeneric" = "you can't invite others here"; +"FolderLinkScreen.AlertTextUnavailablePrivateGroup" = "You don't have the admin rights to share invite links to this private group."; +"FolderLinkScreen.AlertTextUnavailablePublicGroup" = "You don't have the admin rights to share invite links to this group chat."; +"FolderLinkScreen.AlertTextUnavailablePrivateChannel" = "You don't have the admin rights to share invite links to this private channel."; +"FolderLinkScreen.AlertTextUnavailablePublicChannel" = "You don't have the admin rights to share invite links to this channel."; + +"FolderLinkScreen.TitleDescriptionUnavailable" = "You can only share groups and channels in which you are allowed to create invite links."; +"FolderLinkScreen.ChatCountHeaderUnavailable" = "There are no chats in this folder that you can share with others."; +"FolderLinkScreen.ChatsSectionHeaderUnavailable" = "THESE CHATS CANNOT BE SHARED"; + +"FolderLinkScreen.TitleDescriptionDeselected" = "Anyone with this link can add **%@** folder and the chats selected below."; +"FolderLinkScreen.ChatsSectionHeader" = "CHATS"; +"FolderLinkScreen.ChatsSectionHeaderActionSelectAll" = "SELECT ALL"; +"FolderLinkScreen.ChatsSectionHeaderActionDeselectAll" = "DESELECT ALL"; + +"FolderLinkScreen.TitleDescriptionSelectedCount_1" = "the 1 chat"; +"FolderLinkScreen.TitleDescriptionSelectedCount_any" = "the %d chats"; +"FolderLinkScreen.TitleDescriptionSelected" = "Anyone with this link can add **%1$@** folder and %2$@ selected below."; + +"FolderLinkScreen.ChatsSectionHeaderSelected_1" = "1 CHAT SELECTED"; +"FolderLinkScreen.ChatsSectionHeaderSelected_any" = "%d CHATS SELECTED"; + +"FolderLinkScreen.LinkSectionHeader" = "INVITE LINK"; + +"FolderLinkScreen.ContextActionNameLink" = "Name Link"; +"FolderLinkScreen.NameLink.Title" = "Name This Link"; + +"FolderLinkScreen.ToastNewChatAdded" = "People who already used the invite link will be able to join newly added chats."; +"FolderLinkScreen.SaveUnknownError" = "An error occurred while updating the link"; +"FolderLinkScreen.ToastLinkUpdated" = "Link updated"; + +"FolderLinkScreen.Title" = "Share Folder"; + +"FolderLinkScreen.SaveAlertTitle" = "Unsaved Changes"; +"FolderLinkScreen.SaveAlertText" = "You have changed the settings of this folder. Apply changes?"; +"FolderLinkScreen.SaveAlertActionDiscard" = "Discard"; +"FolderLinkScreen.SaveAlertActionApply" = "Apply"; +"FolderLinkScreen.SaveAlertActionContinue" = "Cancel"; + +"FolderLinkScreen.LinkActionCopy" = "Copy"; +"FolderLinkScreen.LinkActionShare" = "Share"; + +"InviteLink.LabelJoinedViaFolder" = "joined via a folder invite link"; + +"ChatListFilter.LinkLabelChatCount_1" = "includes 1 chat"; +"ChatListFilter.LinkLabelChatCount_any" = "includes %d chats"; +"ChatListFilter.LinkActionDelete" = "Delete"; + +"InviteLink.QRCodeFolder.Title" = "Invite by QR Code"; +"InviteLink.QRCodeFolder.Text" = "Everyone on Telegram can scan this code to add this folder and join the chats included in this invite link."; + +"FolderLinkPreview.IconTabLeft" = "All Chats"; +"FolderLinkPreview.IconTabRight" = "Personal"; +"FolderLinkPreview.TitleShare" = "Share Folder"; +"FolderLinkPreview.TitleRemove" = "Remove Folder"; +"FolderLinkPreview.TitleAddFolder" = "Add Folder"; +"FolderLinkPreview.TitleAddChats_1" = "Add %d Chat"; +"FolderLinkPreview.TitleAddChats_any" = "Add %d Chats"; +"FolderLinkPreview.LinkSectionHeader" = "INVITE LINKS"; +"FolderLinkPreview.RemoveSectionSelectedHeader_1" = "%d CHAT TO QUIT"; +"FolderLinkPreview.RemoveSectionSelectedHeader_any" = "%d CHATS TO QUIT"; +"FolderLinkPreview.ChatSectionHeader_1" = "1 CHAT IN THIS FOLDER"; +"FolderLinkPreview.ChatSectionHeader_any" = "%d CHATS IN THIS FOLDER"; +"FolderLinkPreview.ChatSectionJoinHeader_1" = "1 CHAT IN THIS FOLDER TO JOIN"; +"FolderLinkPreview.ChatSectionJoinHeader_any" = "%d CHATS IN THIS FOLDER TO JOIN"; + +"FolderLinkPreview.ToastChatsAddedTitle" = "Folder %@ Updated"; +"FolderLinkPreview.ToastChatsAddedText_1" = "You have joined %d new chat"; +"FolderLinkPreview.ToastChatsAddedText_any" = "You have joined %d new chats"; + +"FolderLinkPreview.ToastFolderAddedTitle" = "Folder %@ Added"; +"FolderLinkPreview.ToastFolderAddedText_1" = "You also joined %d chat"; +"FolderLinkPreview.ToastFolderAddedText_any" = "You also joined %d chats"; + +"FolderLinkPreview.TextLinkList" = "Create more links to set up different access\nlevels for different people."; +"FolderLinkPreview.TextRemoveFolder" = "Do you also want to quit the chats included in this folder?"; +"FolderLinkPreview.TextAllAdded" = "You have already added this\nfolder and its chats."; +"FolderLinkPreview.TextAddFolder" = "Do you want to add a new chat folder\nand join its groups and channels?"; + +"FolderLinkPreview.TextAddChatsCount_1" = "%d chat"; +"FolderLinkPreview.TextAddChatsCount_any" = "%d chats"; +"FolderLinkPreview.TextAddChats" = "Do you want to add **%1$@** to the\nfolder **%2$@**?"; + +"FolderLinkPreview.LabelPeerSubscriber" = "You are already a subscriber"; +"FolderLinkPreview.LabelPeerSubscribers_1" = "%d subscriber"; +"FolderLinkPreview.LabelPeerSubscribers_any" = "%d subscribers"; + +"FolderLinkPreview.LabelPeerMember" = "You are already a member"; +"FolderLinkPreview.LabelPeerMembers_1" = "%d member"; +"FolderLinkPreview.LabelPeerMembers_any" = "%d members"; + +"FolderLinkPreview.ToastAlreadyMemberChannel" = "You are already subscribed to this channel."; +"FolderLinkPreview.ToastAlreadyMemberGroup" = "You are already a member of this group."; + +"FolderLinkPreview.ButtonRemoveFolder" = "Remove Folder"; +"FolderLinkPreview.ButtonRemoveFolderAndChats" = "Remove Folder and Chats"; + +"FolderLinkPreview.ButtonDoNotJoinChats" = "Do Not Join Any Chats"; +"FolderLinkPreview.ButtonJoinChats" = "Join Chats"; +"FolderLinkPreview.ButtonAddFolder" = "Add Folder"; + +"FolderLinkPreview.ToastLeftTitle" = "Folder %@ deleted"; +"FolderLinkPreview.ToastLeftChatsText_1" = "You also left **%d** chat"; +"FolderLinkPreview.ToastLeftChatsText_any" = "You also left **%d** chats"; + +"FolderLinkPreview.ListSelectionSelectAllDynamicPartSelect" = "SELECT"; +"FolderLinkPreview.ListSelectionSelectAllDynamicPartDeselect" = "DESELECT"; +"FolderLinkPreview.ListSelectionSelectAllStaticPartSelect" = "ALL"; +"FolderLinkPreview.ListSelectionSelectAllStaticPartDeselect" = "ALL"; +"FolderLinkPreview.ListSelectionSelectAllFormat" = "{dynamic}{static}"; diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 5bba1511fe..0f02abfe96 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -1599,12 +1599,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController }))) } - //TODO:localize - for filter in filters { if filter.id == filterId, case let .filter(_, title, _, data) = filter { if let filterPeersAreMuted { - items.append(.action(ContextMenuActionItem(text: filterPeersAreMuted.areMuted ? "Unmute All" : "Mute All", textColor: .primary, badge: nil, icon: { theme in + items.append(.action(ContextMenuActionItem(text: filterPeersAreMuted.areMuted ? strongSelf.presentationData.strings.ChatList_ContextUnmuteAll : strongSelf.presentationData.strings.ChatList_ContextMuteAll, textColor: .primary, badge: nil, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: filterPeersAreMuted.areMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { c, f in c.dismiss(completion: { @@ -1623,21 +1621,23 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let iconColor: UIColor = .white let overlayController: UndoOverlayController if !filterPeersAreMuted.areMuted { + let text = strongSelf.presentationData.strings.ChatList_ToastFolderMuted(title).string overlayController = UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [ "Middle.Group 1.Fill 1": iconColor, "Top.Group 1.Fill 1": iconColor, "Bottom.Group 1.Fill 1": iconColor, "EXAMPLE.Group 1.Fill 1": iconColor, "Line.Group 1.Stroke 1": iconColor - ], title: nil, text: "All chats in **\(title)** are now muted", customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }) + ], title: nil, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }) } else { + let text = strongSelf.presentationData.strings.ChatList_ToastFolderUnmuted(title).string overlayController = UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [ "Middle.Group 1.Fill 1": iconColor, "Top.Group 1.Fill 1": iconColor, "Bottom.Group 1.Fill 1": iconColor, "EXAMPLE.Group 1.Fill 1": iconColor, "Line.Group 1.Stroke 1": iconColor - ], title: nil, text: "All chats in **\(title)** are now unmuted", customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }) + ], title: nil, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }) } strongSelf.present(overlayController, in: .current) }) @@ -1645,7 +1645,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } if !data.includePeers.peers.isEmpty && data.categories.isEmpty && !data.excludeRead && !data.excludeMuted && !data.excludeArchived && data.excludePeers.isEmpty { - items.append(.action(ContextMenuActionItem(text: "Share", textColor: .primary, badge: data.hasSharedLinks ? nil : ContextMenuActionBadge(value: "NEW", color: .accent, style: .label), icon: { theme in + items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_ContextMenuShare, textColor: .primary, badge: data.hasSharedLinks ? nil : ContextMenuActionBadge(value: strongSelf.presentationData.strings.ChatList_ContextMenuBadgeNew, color: .accent, style: .label), icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor) }, action: { c, f in c.dismiss(completion: { @@ -2997,8 +2997,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } if hasLinks { - //TODO:localize - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Delete Folder", text: "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder.", actions: [ + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.ChatList_AlertDeleteFolderTitle, text: presentationData.strings.ChatList_AlertDeleteFolderText, actions: [ TextAlertAction(type: .destructiveAction, title: presentationData.strings.Common_Delete, action: { confirmDeleteFolder() }), diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index 261e946cf4..e05badfeb4 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -571,13 +571,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { self.topPanel = topPanel } - //TODO:localize - let title: String - if chatFolderUpdates.availableChatsToJoin == 1 { - title = "1 New Chat Available" - } else { - title = "\(chatFolderUpdates.availableChatsToJoin) New Chats Available" - } + let title: String = self.presentationData.strings.ChatList_PanelNewChatsAvailable(Int32(chatFolderUpdates.availableChatsToJoin)) let topPanelHeight: CGFloat = 44.0 diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift index 3d4d21fdbb..0b888606a1 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift @@ -547,11 +547,9 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry { arguments.expandSection(.exclude) }) case let .inviteLinkHeader(hasLinks): - //TODO:localize - return ItemListSectionHeaderItem(presentationData: presentationData, text: "SHARE FOLDER", badge: hasLinks ? nil : "NEW", sectionId: self.section) + return ItemListSectionHeaderItem(presentationData: presentationData, text: presentationData.strings.ChatListFilter_SectionShare, badge: hasLinks ? nil : presentationData.strings.ChatList_ContextMenuBadgeNew, sectionId: self.section) case let .inviteLinkCreate(hasLinks): - //TODO:localize - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.linkIcon(presentationData.theme), title: hasLinks ? "Create a new Link" : "Create an Invite Link", sectionId: self.section, editing: false, action: { + return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.linkIcon(presentationData.theme), title: hasLinks ? presentationData.strings.ChatListFilter_CreateLink : presentationData.strings.ChatListFilter_CreateLinkNew, sectionId: self.section, editing: false, action: { arguments.createLink() }) case let .inviteLink(_, link): @@ -648,8 +646,7 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio if let currentPreset, let data = currentPreset.data, data.isShared { } else { entries.append(.excludePeersHeader(presentationData.strings.ChatListFolder_ExcludedSectionHeader)) - //TODO:localize - entries.append(.addExcludePeer(title: "Add Chats to Exclude")) + entries.append(.addExcludePeer(title: presentationData.strings.ChatListFilter_ExcludeChatsAction)) var excludeCategoryIndex = 0 for category in ChatListFilterExcludeCategory.allCases { @@ -705,8 +702,7 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio } } - //TODO:localize - entries.append(.inviteLinkInfo(text: hasLinks ? "Create more links to set up different access levels for different people." : "Share access to some of this folder's groups and channels with others.")) + entries.append(.inviteLinkInfo(text: hasLinks ? presentationData.strings.ChatListFilter_LinkListInfo : presentationData.strings.ChatListFilter_LinkListInfoNew)) return entries } @@ -847,30 +843,13 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f removedPeers = data.includePeers.peers.filter({ !includePeers.contains($0) }) } if newPeers.count != 0 { - let title: String - let text: String - - //TODO:localize - if newPeers.count == 1 { - title = "Сhat added to folder" - text = "It will not affect chatlist of the links of this folder" - } else { - title = "\(newPeers.count) chats added to folder" - text = "It will not affect chatlist of the links of this folder" - } + let title: String = presentationData.strings.ChatListFilter_ToastChatsAddedTitle(Int32(newPeers.count)) + let text: String = presentationData.strings.ChatListFilter_ToastChatsAddedText presentUndo(.universal(animation: "anim_add_to_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: title, text: text, customUndoText: nil, timeout: nil)) } else if removedPeers.count != 0 { - let title: String - let text: String - - if newPeers.count == 1 { - title = "Сhat removed from folder" - text = "It will not affect chatlist of the links of this folder" - } else { - title = "\(newPeers.count) chats removed from folder" - text = "It will not affect chatlist of the links of this folder" - } + let title: String = presentationData.strings.ChatListFilter_ToastChatsRemovedTitle(Int32(newPeers.count)) + let text: String = presentationData.strings.ChatListFilter_ToastChatsRemovedText presentUndo(.universal(animation: "anim_remove_from_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: title, text: text, customUndoText: nil, timeout: nil)) } @@ -1327,14 +1306,13 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi let _ = (updatedCurrentPreset |> take(1) |> deliverOnMainQueue).start(next: { currentPreset in if let currentPreset, let data = currentPreset.data, data.hasSharedLinks { - //TODO:localize let title: String let text: String let presentationData = context.sharedContext.currentPresentationData.with { $0 } - title = "Сhat removed from folder" - text = "It will not affect chatlist of the links of this folder" + title = presentationData.strings.ChatListFilter_ToastChatsRemovedTitle(1) + text = presentationData.strings.ChatListFilter_ToastChatsRemovedText presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_remove_from_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: title, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil) } @@ -1394,17 +1372,15 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi }, createLink: { if initialPreset == nil { - //TODO:localize let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let text = "Please finish creating this folder to share it." + let text = presentationData.strings.ChatListFilter_AlertCreateFolderBeforeSharingText presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } else { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let state = stateValue.with({ $0 }) if state.additionallyIncludePeers.isEmpty { - //TODO:localize - let text = "You can’t share folders which have chat types or excluded chats." + let text = presentationData.strings.ChatListFilter_ErrorShareInvalidFolder presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) return @@ -1418,14 +1394,13 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi let _ = (updatedCurrentPreset |> take(1) |> deliverOnMainQueue).start(next: { currentPreset in if let currentPreset, let data = currentPreset.data { - //TODO:localize var unavailableText: String? if !data.categories.isEmpty { - unavailableText = "You can’t share folders which have chat types or excluded chats." + unavailableText = presentationData.strings.ChatListFilter_ErrorShareInvalidFolder } else if data.excludeArchived || data.excludeRead || data.excludeMuted { - unavailableText = "You can’t share folders which have chat types or excluded chats." + unavailableText = presentationData.strings.ChatListFilter_ErrorShareInvalidFolder } else if !data.excludePeers.isEmpty { - unavailableText = "You can’t share folders which have chat types or excluded chats." + unavailableText = presentationData.strings.ChatListFilter_ErrorShareInvalidFolder } if let unavailableText { statusController?.dismiss() @@ -1602,14 +1577,13 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi let _ = (updatedCurrentPreset |> take(1) |> deliverOnMainQueue).start(next: { currentPreset in if let currentPreset, let data = currentPreset.data, data.hasSharedLinks { - //TODO:localize let title: String let text: String let presentationData = context.sharedContext.currentPresentationData.with { $0 } - title = "Сhat removed from folder" - text = "It will not affect chatlist of the links of this folder" + title = presentationData.strings.ChatListFilter_ToastChatsRemovedTitle(1) + text = presentationData.strings.ChatListFilter_ToastChatsRemovedText presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_remove_from_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: title, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil) } @@ -1790,8 +1764,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi TextAlertAction(type: .genericAction, title: presentationData.strings.ChatListFolder_DiscardDiscard, action: { dismissImpl?() }), - //TODO:localize - TextAlertAction(type: .defaultAction, title: "Save", action: { + TextAlertAction(type: .defaultAction, title: presentationData.strings.ChatListFilter_SaveAlertActionSave, action: { applyImpl?(false, { dismissImpl?() }) @@ -1932,11 +1905,13 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec })) }, error: { error in completed() - //TODO:localize + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let text: String switch error { case .generic: - text = "An error occurred" + text = presentationData.strings.ChatListFilter_CreateLinkUnknownError case let .sharedFolderLimitExceeded(limit, _): let limitController = context.sharedContext.makePremiumLimitController(context: context, subject: .membershipInSharedFolders, count: limit, action: { pushPremiumController(PremiumIntroScreen(context: context, source: .membershipInSharedFolders)) @@ -1966,10 +1941,8 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec return case .someUserTooManyChannels: - //TODO:localize - text = "One of the groups in this folder can’t be added because one of its admins has too many groups and channels." + text = presentationData.strings.ChatListFilter_CreateLinkErrorSomeoneHasChannelLimit } - let presentationData = context.sharedContext.currentPresentationData.with { $0 } presentController(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])) }) } diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift index 460e2b3722..6bcb8e8954 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift @@ -223,8 +223,7 @@ private func chatListFilterPresetListControllerEntries(presentationData: Present entries.append(.listHeader(presentationData.strings.ChatListFolderSettings_FoldersSection)) - //TODO:localize - entries.append(.addItem(text: "Create a Folder", isEditing: state.isEditing)) + entries.append(.addItem(text: presentationData.strings.ChatListFilterList_CreateFolder, isEditing: state.isEditing)) if !filters.isEmpty || suggestedFilters.isEmpty { var folderCount = 0 @@ -450,8 +449,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch } if hasLinks { - //TODO:localize - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Delete Folder", text: "Are you sure you want to delete this folder? This will also deactivate all the invite links used to share this folder.", actions: [ + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.ChatList_AlertDeleteFolderTitle, text: presentationData.strings.ChatList_AlertDeleteFolderText, actions: [ TextAlertAction(type: .destructiveAction, title: presentationData.strings.Common_Delete, action: { confirmDeleteFolder() }), diff --git a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift index be5aef5480..7e188fd8ca 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift @@ -221,8 +221,7 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode { switch item.notice { case .chatFolderUpdates: - //TODO:locallize - strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: "Hide", icon: .none, color: item.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.theme.list.itemDisclosureActions.destructive.foregroundColor)])) + strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: item.strings.ChatList_HideAction, icon: .none, color: item.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.theme.list.itemDisclosureActions.destructive.foregroundColor)])) default: strongSelf.setRevealOptions((left: [], right: [])) } diff --git a/submodules/InviteLinksUI/Sources/FolderInviteLinkListController.swift b/submodules/InviteLinksUI/Sources/FolderInviteLinkListController.swift index 4d4a17c61b..ad43b752f7 100644 --- a/submodules/InviteLinksUI/Sources/FolderInviteLinkListController.swift +++ b/submodules/InviteLinksUI/Sources/FolderInviteLinkListController.swift @@ -170,7 +170,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry { case let .mainLinkHeader(text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .mainLink(link, isGenerating): - return ItemListFolderInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: link, count: 0, peers: [], displayButton: true, enableButton: !isGenerating, buttonTitle: link != nil ? "Copy" : "Generate Invite Link", secondaryButtonTitle: link != nil ? "Share" : nil, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: { + return ItemListFolderInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: link, count: 0, peers: [], displayButton: true, enableButton: !isGenerating, buttonTitle: presentationData.strings.FolderLinkScreen_LinkActionCopy, secondaryButtonTitle: link != nil ? presentationData.strings.FolderLinkScreen_LinkActionShare : nil, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: { if let link { arguments.copyLink(link.link) } @@ -196,7 +196,6 @@ private enum InviteLinksListEntry: ItemListNodeEntry { case let .peersInfo(text): return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section) case let .peer(_, peer, isSelected, disabledReasonText): - //TODO:localize return ItemListPeerItem( presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), @@ -204,7 +203,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry { context: arguments.context, peer: peer, presence: nil, - text: .text(disabledReasonText ?? "you can invite others here", .secondary), + text: .text(disabledReasonText ?? presentationData.strings.FolderLinkScreen_LabelCanInvite, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: ItemListPeerItemSwitch(value: isSelected, style: .leftCheck, isEnabled: disabledReasonText == nil), @@ -232,8 +231,6 @@ private func folderInviteLinkListControllerEntries( ) -> [InviteLinksListEntry] { var entries: [InviteLinksListEntry] = [] - //TODO:localize - var infoString: String? let chatCountString: String let peersHeaderString: String @@ -244,34 +241,26 @@ private func folderInviteLinkListControllerEntries( var selectAllString: String? if !canShareChats { - infoString = "You can only share groups and channels in which you are allowed to create invite links." - chatCountString = "There are no chats in this folder that you can share with others." - peersHeaderString = "THESE CHATS CANNOT BE SHARED" + infoString = presentationData.strings.FolderLinkScreen_TitleDescriptionUnavailable + chatCountString = presentationData.strings.FolderLinkScreen_ChatCountHeaderUnavailable + peersHeaderString = presentationData.strings.FolderLinkScreen_ChatsSectionHeaderUnavailable } else if state.selectedPeerIds.isEmpty { - chatCountString = "Anyone with this link can add **\(title)** folder and the chats selected below." - peersHeaderString = "CHATS" + chatCountString = presentationData.strings.FolderLinkScreen_TitleDescriptionDeselected(title).string + peersHeaderString = presentationData.strings.FolderLinkScreen_ChatsSectionHeader if allPeers.count > 1 { - selectAllString = allSelected ? "DESELECT ALL" : "SELECT ALL" - } - } else if state.selectedPeerIds.count == 1 { - chatCountString = "Anyone with this link can add **\(title)** folder and the 1 chat selected below." - peersHeaderString = "1 CHAT SELECTED" - if allPeers.count > 1 { - selectAllString = allSelected ? "DESELECT ALL" : "SELECT ALL" + selectAllString = allSelected ? presentationData.strings.FolderLinkScreen_ChatsSectionHeaderActionDeselectAll : presentationData.strings.FolderLinkScreen_ChatsSectionHeaderActionSelectAll } } else { - chatCountString = "Anyone with this link can add **\(title)** folder and the \(state.selectedPeerIds.count) chats selected below." - peersHeaderString = "\(state.selectedPeerIds.count) CHATS SELECTED" + chatCountString = presentationData.strings.FolderLinkScreen_TitleDescriptionSelected(title, presentationData.strings.FolderLinkScreen_TitleDescriptionSelectedCount(Int32(state.selectedPeerIds.count))).string + peersHeaderString = presentationData.strings.FolderLinkScreen_ChatsSectionHeaderSelected(Int32(state.selectedPeerIds.count)) if allPeers.count > 1 { - selectAllString = allSelected ? "DESELECT ALL" : "SELECT ALL" + selectAllString = allSelected ? presentationData.strings.FolderLinkScreen_ChatsSectionHeaderActionDeselectAll : presentationData.strings.FolderLinkScreen_ChatsSectionHeaderActionSelectAll } } entries.append(.header(chatCountString)) - //TODO:localize - if canShareChats { - entries.append(.mainLinkHeader("INVITE LINK")) + entries.append(.mainLinkHeader(presentationData.strings.FolderLinkScreen_LinkSectionHeader)) entries.append(.mainLink(link: state.currentLink, isGenerating: state.generatingLink)) } @@ -290,12 +279,12 @@ private func folderInviteLinkListControllerEntries( if !canShareLinkToPeer(peer: peer) { if case let .user(user) = peer { if user.botInfo != nil { - disabledReasonText = "you can't share chats with bots" + disabledReasonText = presentationData.strings.FolderLinkScreen_LabelUnavailableBot } else { - disabledReasonText = "you can't share private chats" + disabledReasonText = presentationData.strings.FolderLinkScreen_LabelUnavailableUser } } else { - disabledReasonText = "you can't invite others here" + disabledReasonText = presentationData.strings.FolderLinkScreen_LabelUnavailableGeneric } } entries.append(.peer(index: entries.count, peer: peer, isSelected: state.selectedPeerIds.contains(peer.id), disabledReasonText: disabledReasonText)) @@ -420,15 +409,14 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese let presentationData = context.sharedContext.currentPresentationData.with { $0 } var items: [ContextMenuItem] = [] - //TODO:localize - items.append(.action(ContextMenuActionItem(text: "Name Link", icon: { theme in + items.append(.action(ContextMenuActionItem(text: presentationData.strings.FolderLinkScreen_ContextActionNameLink, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Pencil"), color: theme.contextMenu.primaryColor) }, action: { _, f in f(.dismissWithoutContent) let state = stateValue.with({ $0 }) - let promptController = promptController(sharedContext: context.sharedContext, updatedPresentationData: updatedPresentationData, text: "Name This Link", titleFont: .bold, value: state.title ?? "", characterLimit: 32, apply: { value in + let promptController = promptController(sharedContext: context.sharedContext, updatedPresentationData: updatedPresentationData, text: presentationData.strings.FolderLinkScreen_NameLink_Title, titleFont: .bold, value: state.title ?? "", characterLimit: 32, apply: { value in if let value { updateState { state in var state = state @@ -481,6 +469,8 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture) presentInGlobalOverlayImpl?(contextController) }, peerAction: { peer, isEnabled in + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + if isEnabled { var added = false updateState { state in @@ -503,17 +493,15 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese didDisplayAddPeerNotice = true dismissTooltipsImpl?() - //TODO:localize - displayTooltipImpl?(.info(title: nil, text: "People who already used the invite link will be able to join newly added chats.", timeout: 8), true) + displayTooltipImpl?(.info(title: nil, text: presentationData.strings.FolderLinkScreen_ToastNewChatAdded, timeout: 8), true) } } else { - //TODO:localize let text: String if case let .user(user) = peer { if user.botInfo != nil { - text = "You can't share chats with bots" + text = presentationData.strings.FolderLinkScreen_AlertTextUnavailableBot } else { - text = "You can't share private chats" + text = presentationData.strings.FolderLinkScreen_AlertTextUnavailableUser } } else { var isGroup = true @@ -523,15 +511,15 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese } if isGroup { if isPrivate { - text = "You don't have the admin rights to share invite links to this private group." + text = presentationData.strings.FolderLinkScreen_AlertTextUnavailablePrivateGroup } else { - text = "You don't have the admin rights to share invite links to this group chat." + text = presentationData.strings.FolderLinkScreen_AlertTextUnavailablePublicGroup } } else { if isPrivate { - text = "You don't have the admin rights to share invite links to this private channel." + text = presentationData.strings.FolderLinkScreen_AlertTextUnavailablePrivateChannel } else { - text = "You don't have the admin rights to share invite links to this channel." + text = presentationData.strings.FolderLinkScreen_AlertTextUnavailablePublicChannel } } } @@ -605,12 +593,11 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese dismissTooltipsImpl?() let presentationData = context.sharedContext.currentPresentationData.with { $0 } - //TODO:localize - presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "An error occurred.", timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil) + presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.FolderLinkScreen_SaveUnknownError, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil) }, completed: { + let presentationData = context.sharedContext.currentPresentationData.with { $0 } linkUpdated(ExportedChatFolderLink(title: state.title ?? "", link: currentLink.link, peerIds: Array(state.selectedPeerIds), isRevoked: false)) - //TODO:localize - displayTooltipImpl?(.info(title: nil, text: "Link updated", timeout: 3), false) + displayTooltipImpl?(.info(title: nil, text: presentationData.strings.FolderLinkScreen_ToastLinkUpdated, timeout: 3), false) dismissImpl?() })) @@ -666,10 +653,9 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese animateChanges = true } - //TODO:localize let title: ItemListControllerTitle - var folderTitle = "Share Folder" + var folderTitle = presentationData.strings.FolderLinkScreen_Title if let title = state.title, !title.isEmpty { folderTitle = title } @@ -742,13 +728,12 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese if hasChanges { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - //TODO:localize - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Unsaved Changes", text: "You have changed the settings of this folder. Apply changes?", actions: [ - TextAlertAction(type: .genericAction, title: "Discard", action: { + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.FolderLinkScreen_SaveAlertTitle, text: presentationData.strings.FolderLinkScreen_SaveAlertText, actions: [ + TextAlertAction(type: .genericAction, title: presentationData.strings.FolderLinkScreen_SaveAlertActionDiscard, action: { f() dismissImpl?() }), - TextAlertAction(type: .defaultAction, title: state.selectedPeerIds.isEmpty ? "Continue" : "Apply", action: { + TextAlertAction(type: .defaultAction, title: state.selectedPeerIds.isEmpty ? presentationData.strings.FolderLinkScreen_SaveAlertActionApply : presentationData.strings.FolderLinkScreen_SaveAlertActionContinue, action: { applyChangesImpl?() }) ]), nil) diff --git a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift index 794cb8df90..5596edb62b 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift @@ -227,8 +227,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable { case let .importer(_, _, dateTimeFormat, peer, date, joinedViaFolderLink, loading): let dateString: String if joinedViaFolderLink { - //TODO:localize - dateString = "joined via a folder invite link" + dateString = presentationData.strings.InviteLink_LabelJoinedViaFolder } else { dateString = stringForFullDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: dateTimeFormat) } diff --git a/submodules/InviteLinksUI/Sources/ItemListFolderInviteLinkListItem.swift b/submodules/InviteLinksUI/Sources/ItemListFolderInviteLinkListItem.swift index 8173bb57a5..7e75b08bbe 100644 --- a/submodules/InviteLinksUI/Sources/ItemListFolderInviteLinkListItem.swift +++ b/submodules/InviteLinksUI/Sources/ItemListFolderInviteLinkListItem.swift @@ -308,12 +308,7 @@ public class ItemListFolderInviteLinkListItemNode: ItemListRevealOptionsItemNode titleText = invite.title } - //TODO:localize - if invite.peerIds.count == 1 { - subtitleText = "includes 1 chat" - } else { - subtitleText = "includes \(invite.peerIds.count) chats" - } + subtitleText = item.presentationData.strings.ChatListFilter_LinkLabelChatCount(Int32(invite.peerIds.count)) } else { titleText = " " subtitleText = " " @@ -519,8 +514,7 @@ public class ItemListFolderInviteLinkListItemNode: ItemListRevealOptionsItemNode strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset) if item.removeAction != nil { - //TODO:localize - strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: "Delete", icon: .none, color: item.presentationData.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.presentationData.theme.list.itemDisclosureActions.destructive.foregroundColor)])) + strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: item.presentationData.strings.ChatListFilter_LinkActionDelete, icon: .none, color: item.presentationData.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.presentationData.theme.list.itemDisclosureActions.destructive.foregroundColor)])) } else { strongSelf.setRevealOptions((left: [], right: [])) } diff --git a/submodules/QrCodeUI/Sources/QrCodeScreen.swift b/submodules/QrCodeUI/Sources/QrCodeScreen.swift index 86330a046b..08dff93dac 100644 --- a/submodules/QrCodeUI/Sources/QrCodeScreen.swift +++ b/submodules/QrCodeUI/Sources/QrCodeScreen.swift @@ -239,9 +239,8 @@ public final class QrCodeScreen: ViewController { title = self.presentationData.strings.InviteLink_QRCode_Title text = isGroup ? self.presentationData.strings.InviteLink_QRCode_Info : self.presentationData.strings.InviteLink_QRCode_InfoChannel case .chatFolder: - //TODO:localize - title = "Invite by QR Code" - text = "Everyone on Telegram can scan this code to add this folder and join the chats included in this invite link." + title = self.presentationData.strings.InviteLink_QRCodeFolder_Title + text = self.presentationData.strings.InviteLink_QRCodeFolder_Text default: title = "" text = "" diff --git a/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/ChatFolderLinkHeaderComponent.swift b/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/ChatFolderLinkHeaderComponent.swift index c3f97c1ef4..b58d9105de 100644 --- a/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/ChatFolderLinkHeaderComponent.swift +++ b/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/ChatFolderLinkHeaderComponent.swift @@ -151,9 +151,8 @@ final class ChatFolderLinkHeaderComponent: Component { let badgeSpacing: CGFloat = 6.0 if themeUpdated { - //TODO:localize - let leftString = NSAttributedString(string: "All Chats", font: Font.semibold(14.0), textColor: component.theme.list.freeTextColor) - let rightString = NSAttributedString(string: "Personal", font: Font.semibold(14.0), textColor: component.theme.list.freeTextColor) + let leftString = NSAttributedString(string: component.strings.FolderLinkPreview_IconTabLeft, font: Font.semibold(14.0), textColor: component.theme.list.freeTextColor) + let rightString = NSAttributedString(string: component.strings.FolderLinkPreview_IconTabRight, font: Font.semibold(14.0), textColor: component.theme.list.freeTextColor) let leftStringBounds = leftString.boundingRect(with: CGSize(width: 200.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil) let rightStringBounds = rightString.boundingRect(with: CGSize(width: 200.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil) diff --git a/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/ChatFolderLinkPreviewScreen.swift b/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/ChatFolderLinkPreviewScreen.swift index 848ac5fe1e..b91f2cbd83 100644 --- a/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/ChatFolderLinkPreviewScreen.swift +++ b/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/ChatFolderLinkPreviewScreen.swift @@ -388,12 +388,10 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { var allChatsAdded = false var canAddChatCount = 0 if case .linkList = component.subject { - //TODO:localize - titleString = "Share Folder" + titleString = environment.strings.FolderLinkPreview_TitleShare } else if let linkContents = component.linkContents { - //TODO:localize if case .remove = component.subject { - titleString = "Remove Folder" + titleString = environment.strings.FolderLinkPreview_TitleRemove } else if linkContents.localFilterId != nil { if linkContents.alreadyMemberPeerIds == Set(linkContents.peers.map(\.id)) { allChatsAdded = true @@ -401,14 +399,12 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { canAddChatCount = linkContents.peers.map(\.id).count - linkContents.alreadyMemberPeerIds.count if allChatsAdded { - titleString = "Add Folder" - } else if canAddChatCount == 1 { - titleString = "Add \(canAddChatCount) chat" + titleString = environment.strings.FolderLinkPreview_TitleAddFolder } else { - titleString = "Add \(canAddChatCount) chats" + titleString = environment.strings.FolderLinkPreview_TitleAddChats(Int32(canAddChatCount)) } } else { - titleString = "Add Folder" + titleString = environment.strings.FolderLinkPreview_TitleAddFolder } } else { titleString = " " @@ -464,26 +460,17 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { let text: String if case .linkList = component.subject { - text = "Create more links to set up different access\nlevels for different people." + text = environment.strings.FolderLinkPreview_TextLinkList } else if let linkContents = component.linkContents { if case .remove = component.subject { - text = "Do you also want to quit the chats included in this folder?" + text = environment.strings.FolderLinkPreview_TextRemoveFolder } else if allChatsAdded { - text = "You have already added this\nfolder and its chats." + text = environment.strings.FolderLinkPreview_TextAllAdded } else if linkContents.localFilterId == nil { - text = "Do you want to add a new chat folder\nand join its groups and channels?" + text = environment.strings.FolderLinkPreview_TextAddFolder } else { - let chatCountString: String - if canAddChatCount == 1 { - chatCountString = "1 chat" - } else { - chatCountString = "\(canAddChatCount) chats" - } - if let title = linkContents.title { - text = "Do you want to add **\(chatCountString)** to the\nfolder **\(title)**?" - } else { - text = "Do you want to add **\(chatCountString)** chats to the\nfolder?" - } + let chatCountString: String = environment.strings.FolderLinkPreview_TextAddChatsCount(Int32(canAddChatCount)) + text = environment.strings.FolderLinkPreview_TextAddChats(chatCountString, linkContents.title ?? "").string } } else { text = " " @@ -544,7 +531,7 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { theme: environment.theme, sideInset: 0.0, iconName: "Contact List/LinkActionIcon", - title: "Create a New Link", + title: environment.strings.InviteLink_Create, hasNext: !self.linkListItems.isEmpty, action: { [weak self] in self?.openCreateLink() @@ -582,12 +569,7 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { self.items[id] = item } - let subtitle: String - if link.peerIds.count == 1 { - subtitle = "includes 1 chat" - } else { - subtitle = "includes \(link.peerIds.count) chats" - } + let subtitle: String = environment.strings.ChatListFilter_LinkLabelChatCount(Int32(link.peerIds.count)) let itemComponent = LinkListItemComponent( theme: environment.theme, @@ -713,15 +695,15 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { var subtitle: String? if case let .channel(channel) = peer, case .broadcast = channel.info { if linkContents.alreadyMemberPeerIds.contains(peer.id) { - subtitle = "You are already a subscriber" + subtitle = environment.strings.FolderLinkPreview_LabelPeerSubscriber } else if let memberCount = linkContents.memberCounts[peer.id] { - subtitle = "\(memberCount) subscribers" + subtitle = environment.strings.FolderLinkPreview_LabelPeerSubscribers(Int32(memberCount)) } } else { if linkContents.alreadyMemberPeerIds.contains(peer.id) { - subtitle = "You are already a member" + subtitle = environment.strings.FolderLinkPreview_LabelPeerMember } else if let memberCount = linkContents.memberCounts[peer.id] { - subtitle = "\(memberCount) participants" + subtitle = environment.strings.FolderLinkPreview_LabelPeerMembers(Int32(memberCount)) } } @@ -753,9 +735,9 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } let text: String if case let .channel(channel) = peer, case .broadcast = channel.info { - text = "You are already a member of this channel." + text = presentationData.strings.FolderLinkPreview_ToastAlreadyMemberChannel } else { - text = "You are already a member of this group." + text = presentationData.strings.FolderLinkPreview_ToastAlreadyMemberGroup } controller.present(UndoOverlayController(presentationData: presentationData, content: .peers(context: component.context, peers: [peer], title: nil, text: text, customUndoText: nil), elevatedLayout: false, action: { _ in true }), in: .current) } else { @@ -798,43 +780,59 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { let listHeaderTitle: String if case .linkList = component.subject { - listHeaderTitle = "INVITE LINKS" + listHeaderTitle = environment.strings.FolderLinkPreview_LinkSectionHeader } else if let linkContents = component.linkContents { if case .remove = component.subject { - if linkContents.peers.count == 1 { - listHeaderTitle = "1 CHAT TO QUIT" - } else { - listHeaderTitle = "\(linkContents.peers.count) CHATS TO QUIT" - } + listHeaderTitle = environment.strings.FolderLinkPreview_RemoveSectionSelectedHeader(Int32(linkContents.peers.count)) } else if allChatsAdded { - if linkContents.peers.count == 1 { - listHeaderTitle = "1 CHAT IN THIS FOLDER" - } else { - listHeaderTitle = "\(linkContents.peers.count) CHATS IN THIS FOLDER" - } + listHeaderTitle = environment.strings.FolderLinkPreview_ChatSectionHeader(Int32(linkContents.peers.count)) } else { - if linkContents.peers.count == 1 { - listHeaderTitle = "1 CHAT IN FOLDER TO JOIN" - } else { - listHeaderTitle = "\(linkContents.peers.count) CHATS IN FOLDER TO JOIN" - } + listHeaderTitle = environment.strings.FolderLinkPreview_ChatSectionJoinHeader(Int32(linkContents.peers.count)) } } else { listHeaderTitle = " " } - //TODO:localize - let listHeaderActionItems: [AnimatedCounterComponent.Item] + var listHeaderActionItems: [AnimatedCounterComponent.Item] = [] + + let dynamicIndex = environment.strings.FolderLinkPreview_ListSelectionSelectAllFormat.range(of: "{dynamic}") + let staticIndex = environment.strings.FolderLinkPreview_ListSelectionSelectAllFormat.range(of: "{static}") + var headerActionItemIndices: [Int: Int] = [:] + if let dynamicIndex, let staticIndex { + if dynamicIndex.lowerBound < staticIndex.lowerBound { + headerActionItemIndices[0] = 0 + headerActionItemIndices[1] = 1 + } else { + headerActionItemIndices[0] = 1 + headerActionItemIndices[1] = 0 + } + } else if dynamicIndex != nil { + headerActionItemIndices[0] = 0 + } else if staticIndex != nil { + headerActionItemIndices[1] = 0 + } + + let dynamicItem: AnimatedCounterComponent.Item + let staticItem: AnimatedCounterComponent.Item + if self.selectedItems.count == self.items.count { - listHeaderActionItems = [ - AnimatedCounterComponent.Item(id: AnyHashable(0), text: "DESELECT", numericValue: 0), - AnimatedCounterComponent.Item(id: AnyHashable(1), text: "ALL", numericValue: 1) - ] + dynamicItem = AnimatedCounterComponent.Item(id: AnyHashable(0), text: environment.strings.FolderLinkPreview_ListSelectionSelectAllDynamicPartDeselect, numericValue: 0) + staticItem = AnimatedCounterComponent.Item(id: AnyHashable(1), text: environment.strings.FolderLinkPreview_ListSelectionSelectAllStaticPartDeselect, numericValue: 1) } else { - listHeaderActionItems = [ - AnimatedCounterComponent.Item(id: AnyHashable(0), text: "SELECT", numericValue: 1), - AnimatedCounterComponent.Item(id: AnyHashable(1), text: "ALL", numericValue: 1) - ] + dynamicItem = AnimatedCounterComponent.Item(id: AnyHashable(0), text: environment.strings.FolderLinkPreview_ListSelectionSelectAllDynamicPartSelect, numericValue: 1) + staticItem = AnimatedCounterComponent.Item(id: AnyHashable(1), text: environment.strings.FolderLinkPreview_ListSelectionSelectAllStaticPartSelect, numericValue: 1) + } + + if let dynamicIndex = headerActionItemIndices[0], let staticIndex = headerActionItemIndices[1] { + if dynamicIndex < staticIndex { + listHeaderActionItems = [dynamicItem, staticItem] + } else { + listHeaderActionItems = [staticItem, dynamicItem] + } + } else if headerActionItemIndices[0] != nil { + listHeaderActionItems = [dynamicItem] + } else if headerActionItemIndices[1] != nil { + listHeaderActionItems = [staticItem] } let listHeaderBody = MarkdownAttributeSet(font: Font.with(size: 13.0, design: .regular, traits: [.monospacedNumbers]), textColor: environment.theme.list.freeTextColor) @@ -928,23 +926,23 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { if case .remove = component.subject { actionButtonBadge = self.selectedItems.count if self.selectedItems.isEmpty { - actionButtonTitle = "Remove Folder" + actionButtonTitle = environment.strings.FolderLinkPreview_ButtonRemoveFolder } else { - actionButtonTitle = "Remove Folder and Chats" + actionButtonTitle = environment.strings.FolderLinkPreview_ButtonRemoveFolderAndChats } } else if allChatsAdded { actionButtonBadge = 0 - actionButtonTitle = "OK" + actionButtonTitle = environment.strings.Common_OK } else if let linkContents = component.linkContents { actionButtonBadge = max(0, self.selectedItems.count - (linkContents.peers.count - canAddChatCount)) if linkContents.localFilterId != nil { if self.selectedItems.isEmpty { - actionButtonTitle = "Do Not Join Any Chats" + actionButtonTitle = environment.strings.FolderLinkPreview_ButtonDoNotJoinChats } else { - actionButtonTitle = "Join Chats" + actionButtonTitle = environment.strings.FolderLinkPreview_ButtonJoinChats } } else { - actionButtonTitle = "Add Folder" + actionButtonTitle = environment.strings.FolderLinkPreview_ButtonAddFolder } } else { actionButtonTitle = " " @@ -987,17 +985,13 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { let folderTitle = linkContents.title ?? "" + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }) + var additionalText: String? if !self.selectedItems.isEmpty { - if self.selectedItems.count == 1 { - additionalText = "You also left **1** chat" - } else { - additionalText = "You also left **\(self.selectedItems.count)** chats" - } + additionalText = presentationData.strings.FolderLinkPreview_ToastLeftChatsText(Int32(self.selectedItems.count)) } - let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }) - var chatListController: ChatListController? if let navigationController = controller.navigationController as? NavigationController { for viewController in navigationController.viewControllers.reversed() { @@ -1025,7 +1019,7 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { let selectedItems = self.selectedItems let undoOverlayController = UndoOverlayController( presentationData: presentationData, - content: .removedChat(title: "Folder \(folderTitle) deleted", text: additionalText), + content: .removedChat(title: presentationData.strings.FolderLinkPreview_ToastLeftTitle(folderTitle).string, text: additionalText), elevatedLayout: false, action: { value in if case .commit = value { @@ -1106,7 +1100,6 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { return } - //TODO:localize let presentationData = context.sharedContext.currentPresentationData.with({ $0 }) var isUpdates = false @@ -1119,29 +1112,15 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { } if isUpdates { - let chatCountString: String - if result.newChatCount == 1 { - chatCountString = "1 new chat" - } else { - chatCountString = "\(result.newChatCount) new chats" - } - - chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_add_to_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: "Folder \(result.title) Updated", text: "You have joined \(chatCountString)", customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current) + chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_add_to_folder", scale: 0.1, colors: ["__allcolors__": UIColor.white], title: presentationData.strings.FolderLinkPreview_ToastChatsAddedTitle(result.title).string, text: presentationData.strings.FolderLinkPreview_ToastChatsAddedText(Int32(result.newChatCount)), customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current) } else if result.newChatCount != 0 { - let chatCountString: String - if result.newChatCount == 1 { - chatCountString = "1 chat" - } else { - chatCountString = "\(result.newChatCount) chats" - } - let animationBackgroundColor: UIColor if presentationData.theme.overallDarkAppearance { animationBackgroundColor = presentationData.theme.rootController.tabBar.backgroundColor } else { animationBackgroundColor = UIColor(rgb: 0x474747) } - chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_success", scale: 1.0, colors: ["info1.info1.stroke": animationBackgroundColor, "info2.info2.Fill": animationBackgroundColor], title: "Folder \(result.title) Added", text: "You also joined \(chatCountString)", customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current) + chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_success", scale: 1.0, colors: ["info1.info1.stroke": animationBackgroundColor, "info2.info2.Fill": animationBackgroundColor], title: presentationData.strings.FolderLinkPreview_ToastFolderAddedTitle(result.title).string, text: presentationData.strings.FolderLinkPreview_ToastFolderAddedText(Int32(result.newChatCount)), customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current) } else { let animationBackgroundColor: UIColor if presentationData.theme.overallDarkAppearance { @@ -1149,7 +1128,7 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { } else { animationBackgroundColor = UIColor(rgb: 0x474747) } - chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_success", scale: 1.0, colors: ["info1.info1.stroke": animationBackgroundColor, "info2.info2.Fill": animationBackgroundColor], title: "Folder \(result.title) Added", text: "", customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current) + chatListController.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_success", scale: 1.0, colors: ["info1.info1.stroke": animationBackgroundColor, "info2.info2.Fill": animationBackgroundColor], title: presentationData.strings.FolderLinkPreview_ToastFolderAddedTitle(result.title).string, text: "", customUndoText: nil, timeout: 5), elevatedLayout: false, action: { _ in true }), in: .current) } }) } @@ -1423,11 +1402,12 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { let context = component.context let navigationController = controller.navigationController as? NavigationController - //TODO:localize + let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } + let text: String switch error { case .generic: - text = "An error occurred" + text = presentationData.strings.ChatListFilter_CreateLinkUnknownError case let .sharedFolderLimitExceeded(limit, _): let limitController = component.context.sharedContext.makePremiumLimitController(context: component.context, subject: .membershipInSharedFolders, count: limit, action: { [weak navigationController] in guard let navigationController else { @@ -1472,10 +1452,8 @@ private final class ChatFolderLinkPreviewScreenComponent: Component { return case .someUserTooManyChannels: - //TODO:localize - text = "One of the groups in this folder can’t be added because one of its admins has too many groups and channels." + text = presentationData.strings.ChatListFilter_CreateLinkErrorSomeoneHasChannelLimit } - let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }) } diff --git a/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/PeerListItemComponent.swift b/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/PeerListItemComponent.swift index 4f8e5a3ad9..d5acbc67b8 100644 --- a/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/PeerListItemComponent.swift +++ b/submodules/TelegramUI/Components/ChatFolderLinkPreviewScreen/Sources/PeerListItemComponent.swift @@ -218,20 +218,19 @@ final class PeerListItemComponent: Component { } } - //TODO:localize let labelData: (String, Bool) if let subtitle = component.subtitle { labelData = (subtitle, false) } else if case .legacyGroup = component.peer { - labelData = ("group", false) + labelData = (component.strings.Group_Status, false) } else if case let .channel(channel) = component.peer { if case .group = channel.info { - labelData = ("group", false) + labelData = (component.strings.Group_Status, false) } else { - labelData = ("channel", false) + labelData = (component.strings.Channel_Status, false) } } else { - labelData = ("group", false) + labelData = (component.strings.Group_Status, false) } let labelSize = self.label.update(