diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index fb7f182b8a..3d17fee461 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8746,3 +8746,101 @@ Sorry for the inconvenience."; "Premium.Translation.Proceed" = "About Telegram Premium"; "Settings.PauseMusicOnRecording" = "Pause Music While Recoding"; + +"Settings.SuggestSetupPasswordTitle" = "Protect Your Account"; +"Settings.SuggestSetupPasswordText" = "Set a password that will be required each time you log in with this phone number."; +"Settings.SuggestSetupPasswordAction" = "Set Additional Password"; + +"Chat.SendNotAllowedText" = "Sending messages is not allowed in this group"; +"Chat.SendNotAllowedPeerText" = "Sending messages is not allowed in %@"; +"Chat.SendNotAllowedPhoto" = "Sending photos is not allowed in this group"; +"Chat.SendNotAllowedVideo" = "Sending videos is not allowed in this group"; +"Chat.SendNotAllowedFile" = "Sending files is not allowed in this group"; +"Chat.SendNotAllowedAudioMessage" = "Sending audio messages is not allowed in this group"; +"Chat.SendNotAllowedVideoMessage" = "Sending video messages is not allowed in this group"; +"Chat.SendNotAllowedMusic" = "Sending music is not allowed in this group"; + +"Chat.SendAllowedContentText" = "The admins of this group only allow to send %1$@."; +"Chat.SendAllowedContentPeerText" = "The admins of %1$@ only allow to send %2$@."; + +"Chat.SendAllowedContentTypeText" = "text messages"; +"Chat.SendAllowedContentTypePhoto" = "photos"; +"Chat.SendAllowedContentTypeVideo" = "videos"; +"Chat.SendAllowedContentTypeVoiceMessage" = "voice messages"; +"Chat.SendAllowedContentTypeVideoMessage" = "video messages"; +"Chat.SendAllowedContentTypeFile" = "files"; +"Chat.SendAllowedContentTypeMusic" = "music"; +"Chat.SendAllowedContentTypeSticker" = "stickers & GIFs"; + +"Channel.BanUser.PermissionSendPhoto" = "Send Photos"; +"Channel.BanUser.PermissionSendVideo" = "Send Videos"; +"Channel.BanUser.PermissionSendMusic" = "Send Music"; +"Channel.BanUser.PermissionSendVoiceMessage" = "Send Audio Messages"; +"Channel.BanUser.PermissionSendVideoMessage" = "Send Video Messages"; +"Channel.BanUser.PermissionSendFile" = "Send Files"; + +"GroupPermission.NoSendPhoto" = "no photos"; +"GroupPermission.NoSendVideo" = "no videos"; +"GroupPermission.NoSendMusic" = "no music"; +"GroupPermission.NoSendVoiceMessage" = "no audio messages"; +"GroupPermission.NoSendVideoMessage" = "no video messages"; +"GroupPermission.NoSendFile" = "no files"; + +"Settings.AutosaveMediaOn" = "On"; +"Settings.AutosaveMediaOff" = "Off"; +"Settings.AutosaveMediaOn" = "On"; +"Settings.AutosaveMediaAllMedia" = "All Media (%@)"; +"Settings.AutosaveMediaPhoto" = "Photos"; +"Settings.AutosaveMediaNoPhoto" = "No Photos"; +"Settings.AutosaveMediaVideo" = "Videos up to %@"; +"Settings.AutosaveMediaNoVideo" = "No Videos"; + +"Settings.SaveToCameraRollSection" = "SAVE TO CAMERA ROLL"; +"Settings.SaveToCameraRollInfo" = "Automatically save all new photos and videos from these chats to your Cameral Roll."; + +"Autosave.TypesSection" = "SAVE TO CAMERA ROLL"; +"Autosave.TypePhoto" = "Photos"; +"Autosave.TypeVideo" = "Videos"; +"Autosave.TypesInfo" = "Automatically save all new media from private chats to your Cameral Roll."; +"Autosave.VideoSizeSection" = "MAXIMUM VIDEO SIZE"; +"Autosave.VideoInfo" = "All downloaded videos in private chats less than %@ will be saved to Cameral Roll."; +"Autosave.ExceptionsSection" = "EXCEPTIONS"; +"Autosave.AddException" = "Add Exception"; +"Autosave.Exception" = "Exception"; +"Autosave.DeleteAllExceptions" = "Delete All Exceptions"; + +"Chat.ErrorInvoiceNotFound" = "Invoice not found."; + +"EmojiStatus.AppliedText" = "Your emoji status has been updated."; +"EmojiPreview.SendEmoji" = "Send Emoji"; +"EmojiPreview.SetAsStatus" = "Set as Status"; +"EmojiPreview.CopyEmoji" = "Copy Emoji"; + +"EmojiSearch.SearchStickersEmptyResult" = "No emoji found"; + +"DataUsage.MediaDirectionIncoming" = "Incoming"; +"DataUsage.MediaDirectionOutgoing" = "Outgoing"; +"DataUsage.InfoTotalUsageSinceTime" = "Your data usage since %@"; +"DataUsage.InfoMobileUsageSinceTime" = "Your mobile data usage since %@"; +"DataUsage.InfoWifiUsageSinceTime" = "Your Wi-Fi data usage since %@"; +"DataUsage.SectionsInfo" = "Tap on each section for detailed view."; +"DataUsage.SectionUsageTotal" = "TOTAL NETWORK USAGE"; +"DataUsage.SectionUsageMobile" = "MOBILE NETWORK USAGE"; +"DataUsage.SectionUsageWifi" = "WI-FI NETWORK USAGE"; +"DataUsage.AutoDownloadSettings" = "Auto-Download Settings"; + +"StorageManagement.SectionMessages" = "Messages"; +"StorageManagement.SectionVoiceMessages" = "Voice Messages"; +"StorageManagement.SectionCalls" = "Calls"; + +"DataUsage.SectionTotalIncoming" = "Data Received"; +"DataUsage.SectionTotalOutgoing" = "Data Sent"; + +"EmojiInput.TabMasks" = "Masks"; +"EmojiInput.TabGifs" = "GIFs"; +"EmojiInput.TabStickers" = "Stickers"; +"EmojiInput.TabEmoji" = "Emoji"; + +"EmojiInput.TrendingEmoji" = "TRENDING EMOJI"; + +"Chat.PlaceholderTextNotAllowed" = "Text not allowed"; diff --git a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift index a68c3d1327..52082e38b3 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift @@ -138,9 +138,8 @@ class ChatListStorageInfoItemNode: ListViewItemNode { textString = NSAttributedString(string: item.strings.ChatList_StorageHintText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor) case .setupPassword: - //TODO:localize - titleString = NSAttributedString(string: "Protect Your Account", font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor) - textString = NSAttributedString(string: "Set a password that will be required each time you log in with this phone number.", font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor) + titleString = NSAttributedString(string: item.strings.Settings_SuggestSetupPasswordTitle, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor) + textString = NSAttributedString(string: item.strings.Settings_SuggestSetupPasswordText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor) case let .premiumUpgrade(discount): let discountString = "\(discount)%" let rawTitleString = item.strings.ChatList_PremiumAnnualUpgradeTitle(discountString) diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 3c8d54b069..d9f4283c40 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -1178,30 +1178,26 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { } if let _ = item as? TGMediaPickerGalleryPhotoItem { if self.bannedSendPhotos != nil { - //TODO:localize - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: "Sending photos is not allowed", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Chat_SendNotAllowedPhoto, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return false } } else if let _ = item as? TGMediaPickerGalleryVideoItem { if self.bannedSendVideos != nil { - //TODO:localize - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: "Sending videos is not allowed", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Chat_SendNotAllowedVideo, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return false } } else if let asset = item as? TGMediaAsset { if asset.isVideo { if self.bannedSendVideos != nil { - //TODO:localize - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: "Sending videos is not allowed", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Chat_SendNotAllowedVideo, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return false } } else { if self.bannedSendPhotos != nil { - //TODO:localize - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: "Sending photos is not allowed", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Chat_SendNotAllowedPhoto, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return false } @@ -1280,30 +1276,26 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { if let self = self, let selectionState = self.interaction?.selectionState { if let _ = item as? TGMediaPickerGalleryPhotoItem { if self.bannedSendPhotos != nil { - //TODO:localize - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: "Sending photos is not allowed", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Chat_SendNotAllowedPhoto, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return false } } else if let _ = item as? TGMediaPickerGalleryVideoItem { if self.bannedSendVideos != nil { - //TODO:localize - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: "Sending videos is not allowed", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Chat_SendNotAllowedVideo, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return false } } else if let asset = item as? TGMediaAsset { if asset.isVideo { if self.bannedSendVideos != nil { - //TODO:localize - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: "Sending videos is not allowed", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Chat_SendNotAllowedVideo, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return false } } else { if self.bannedSendPhotos != nil { - //TODO:localize - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: "Sending photos is not allowed", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Chat_SendNotAllowedPhoto, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return false } diff --git a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift index 834afd1319..5fcd65d6a4 100644 --- a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift @@ -379,7 +379,6 @@ private struct ChannelPermissionsControllerState: Equatable { } func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatBannedRightsFlags, isForum: Bool) -> String { - //TODO:localize if right.contains(.banSendText) { return strings.Channel_BanUser_PermissionSendMessages } else if right.contains(.banSendMedia) { @@ -399,19 +398,19 @@ func stringForGroupPermission(strings: PresentationStrings, right: TelegramChatB } else if right.contains(.banManageTopics) { return strings.Channel_EditAdmin_PermissionCreateTopics } else if right.contains(.banSendPhotos) { - return "Send Photos" + return strings.Channel_BanUser_PermissionSendPhoto } else if right.contains(.banSendVideos) { - return "Send Videos" + return strings.Channel_BanUser_PermissionSendVideo } else if right.contains(.banSendStickers) { return strings.Channel_BanUser_PermissionSendStickersAndGifs } else if right.contains(.banSendMusic) { - return "Send Music" + return strings.Channel_BanUser_PermissionSendMusic } else if right.contains(.banSendFiles) { - return "Send Files" + return strings.Channel_BanUser_PermissionSendFile } else if right.contains(.banSendVoice) { - return "Send Voice Messages" + return strings.Channel_BanUser_PermissionSendVoiceMessage } else if right.contains(.banSendInstantVideos) { - return "Send Video Messages" + return strings.Channel_BanUser_PermissionSendVideoMessage } else { return "" } @@ -423,17 +422,17 @@ func compactStringForGroupPermission(strings: PresentationStrings, right: Telegr } else if right.contains(.banSendMedia) { return strings.GroupPermission_NoSendMedia } else if right.contains(.banSendPhotos) { - return "no photos" + return strings.GroupPermission_NoSendPhoto } else if right.contains(.banSendVideos) { - return "no videos" + return strings.GroupPermission_NoSendVideo } else if right.contains(.banSendMusic) { - return "no music" + return strings.GroupPermission_NoSendMusic } else if right.contains(.banSendFiles) { - return "no files" + return strings.GroupPermission_NoSendFile } else if right.contains(.banSendVoice) { - return "no voice messages" + return strings.GroupPermission_NoSendVoiceMessage } else if right.contains(.banSendInstantVideos) { - return "no video messages" + return strings.GroupPermission_NoSendVideoMessage } else if right.contains(.banSendGifs) { return strings.GroupPermission_NoSendGifs } else if right.contains(.banEmbedLinks) { diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift index 5f3fdd6a94..39b02b74d5 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift @@ -253,7 +253,11 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { private let emojiSearchDisposable = MetaDisposable() private let emojiSearchState = Promise(EmojiSearchState(result: nil, isSearching: false)) - private var emojiSearchStateValue: EmojiSearchState = EmojiSearchState(result: nil, isSearching: false) + private var emojiSearchStateValue = EmojiSearchState(result: nil, isSearching: false) { + didSet { + self.emojiSearchState.set(.single(self.emojiSearchStateValue)) + } + } private var emptyResultEmojis: [TelegramMediaFile] = [] private var stableEmptyResultEmoji: TelegramMediaFile? diff --git a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift index 6d2d1b491d..3c33297a21 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift @@ -574,28 +574,27 @@ private func autosaveLabelAndValue(presentationData: PresentationData, settings: } } - //TODO:localize let value: String if configuration.photo || configuration.video { - value = "On" + value = presentationData.strings.Settings_AutosaveMediaOn } else { - value = "Off" + value = presentationData.strings.Settings_AutosaveMediaOff } var label = "" if configuration.photo && configuration.video { - label.append("All Media (\(dataSizeString(Int(configuration.maximumVideoSize), formatting: DataSizeStringFormatting(presentationData: presentationData))))") + label.append(presentationData.strings.Settings_AutosaveMediaAllMedia(dataSizeString(Int(configuration.maximumVideoSize), formatting: DataSizeStringFormatting(presentationData: presentationData))).string) } else { if configuration.photo { if !label.isEmpty { label.append(", ") } - label.append("Photos") + label.append(presentationData.strings.Settings_AutosaveMediaPhoto) } else if configuration.video { if !label.isEmpty { label.append(", ") } - label.append("Videos up to \(dataSizeString(Int(configuration.maximumVideoSize), formatting: DataSizeStringFormatting(presentationData: presentationData)))") + label.append(presentationData.strings.Settings_AutosaveMediaVideo(dataSizeString(Int(configuration.maximumVideoSize), formatting: DataSizeStringFormatting(presentationData: presentationData))).string) } } @@ -622,17 +621,16 @@ private func dataAndStorageControllerEntries(state: DataAndStorageControllerStat let defaultSettings = MediaAutoDownloadSettings.defaultSettings entries.append(.automaticDownloadReset(presentationData.theme, presentationData.strings.ChatSettings_AutoDownloadReset, data.automaticMediaDownloadSettings.cellular != defaultSettings.cellular || data.automaticMediaDownloadSettings.wifi != defaultSettings.wifi)) - //TODO:localize - entries.append(.autoSaveHeader("SAVE TO CAMERA ROLL")) + entries.append(.autoSaveHeader(presentationData.strings.Settings_SaveToCameraRollSection)) let privateLabelAndValue = autosaveLabelAndValue(presentationData: presentationData, settings: mediaAutoSaveSettings, peerType: .privateChats, exceptionPeers: autosaveExceptionPeers) let groupsLabelAndValue = autosaveLabelAndValue(presentationData: presentationData, settings: mediaAutoSaveSettings, peerType: .groups, exceptionPeers: autosaveExceptionPeers) let channelsLabelAndValue = autosaveLabelAndValue(presentationData: presentationData, settings: mediaAutoSaveSettings, peerType: .channels, exceptionPeers: autosaveExceptionPeers) - entries.append(.autoSaveItem(index: 0, type: .privateChats, title: "Private Chats", label: privateLabelAndValue.label, value: privateLabelAndValue.value)) - entries.append(.autoSaveItem(index: 1, type: .groups, title: "Groups", label: groupsLabelAndValue.label, value: groupsLabelAndValue.value)) - entries.append(.autoSaveItem(index: 2, type: .channels, title: "Channels", label: channelsLabelAndValue.label, value: channelsLabelAndValue.value)) - entries.append(.autoSaveInfo("Automatically save all new photos and videos from these chats to your Cameral Roll.")) + entries.append(.autoSaveItem(index: 0, type: .privateChats, title: presentationData.strings.Notifications_PrivateChats, label: privateLabelAndValue.label, value: privateLabelAndValue.value)) + entries.append(.autoSaveItem(index: 1, type: .groups, title: presentationData.strings.Notifications_GroupChats, label: groupsLabelAndValue.label, value: groupsLabelAndValue.value)) + entries.append(.autoSaveItem(index: 2, type: .channels, title: presentationData.strings.Notifications_Channels, label: channelsLabelAndValue.label, value: channelsLabelAndValue.value)) + entries.append(.autoSaveInfo(presentationData.strings.Settings_SaveToCameraRollInfo)) let dataSaving = effectiveDataSaving(for: data.voiceCallSettings, autodownloadSettings: data.autodownloadSettings) diff --git a/submodules/SettingsUI/Sources/Data and Storage/SaveIncomingMediaController.swift b/submodules/SettingsUI/Sources/Data and Storage/SaveIncomingMediaController.swift index a253a6fcce..53eb0764d9 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/SaveIncomingMediaController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/SaveIncomingMediaController.swift @@ -258,12 +258,11 @@ private func saveIncomingMediaControllerEntries(presentationData: PresentationDa entries.append(.peer(peer: peer, presence: peerPresence)) } - entries.append(.typesHeader("SAVE TO CAMERA ROLL")) + entries.append(.typesHeader(presentationData.strings.Autosave_TypesSection)) - //TODO:localize - entries.append(.typePhotos("Photos", configuration.photo)) - entries.append(.typeVideos("Videos", configuration.video)) - entries.append(.typesInfo("Automatically save all new media from private chats to your Cameral Roll.")) + entries.append(.typePhotos(presentationData.strings.Autosave_TypePhoto, configuration.photo)) + entries.append(.typeVideos(presentationData.strings.Autosave_TypeVideo, configuration.video)) + entries.append(.typesInfo(presentationData.strings.Autosave_TypesInfo)) if configuration.video { let sizeText: String @@ -275,9 +274,9 @@ private func saveIncomingMediaControllerEntries(presentationData: PresentationDa let text = presentationData.strings.AutoDownloadSettings_UpTo(sizeText).string - entries.append(.videoSizeHeader("MAXIMUM VIDEO SIZE")) + entries.append(.videoSizeHeader(presentationData.strings.Autosave_VideoSizeSection)) entries.append(.videoSize(decimalSeparator: presentationData.dateTimeFormat.decimalSeparator, text: text, value: configuration.maximumVideoSize)) - entries.append(.videoInfo("All downloaded videos in private chats less than \(sizeText) will be saved to Cameral Roll.")) + entries.append(.videoInfo(presentationData.strings.Autosave_VideoInfo(sizeText).string)) } if case let .peerType(peerType) = scope { @@ -306,13 +305,12 @@ private func saveIncomingMediaControllerEntries(presentationData: PresentationDa } if filteredExceptions.isEmpty { - //TODO:localize - entries.append(.exceptionsHeader("EXCEPTIONS")) + entries.append(.exceptionsHeader(presentationData.strings.Autosave_ExceptionsSection)) } else { entries.append(.exceptionsHeader(presentationData.strings.Notifications_CategoryExceptions(Int32(filteredExceptions.count)).uppercased())) } - entries.append(.addException("Add Exception")) + entries.append(.addException(presentationData.strings.Autosave_AddException)) var index = 0 for (exceptionPeer, exceptionConfiguration) in filteredExceptions { @@ -321,23 +319,23 @@ private func saveIncomingMediaControllerEntries(presentationData: PresentationDa if !label.isEmpty { label.append(", ") } - label.append("Photos") + label.append(presentationData.strings.Settings_AutosaveMediaPhoto) } else { if !label.isEmpty { label.append(", ") } - label.append("No Photos") + label.append(presentationData.strings.Settings_AutosaveMediaNoPhoto) } if exceptionConfiguration.video { if !label.isEmpty { label.append(", ") } - label.append("Videos up to \(dataSizeString(Int(exceptionConfiguration.maximumVideoSize), formatting: DataSizeStringFormatting(presentationData: presentationData)))") + label.append(presentationData.strings.Settings_AutosaveMediaVideo(dataSizeString(Int(exceptionConfiguration.maximumVideoSize), formatting: DataSizeStringFormatting(presentationData: presentationData))).string) } else { if !label.isEmpty { label.append(", ") } - label.append("No Videos") + label.append(presentationData.strings.Settings_AutosaveMediaNoVideo) } entries.append(.exceptionItem(index: index, peer: exceptionPeer, label: label)) @@ -345,7 +343,7 @@ private func saveIncomingMediaControllerEntries(presentationData: PresentationDa } if !filteredExceptions.isEmpty { - entries.append(.deleteAllExceptions("Delete All Exceptions")) + entries.append(.deleteAllExceptions(presentationData.strings.Autosave_DeleteAllExceptions)) } } @@ -588,8 +586,7 @@ func saveIncomingMediaController(context: AccountContext, scope: SaveIncomingMed let presentationData = context.sharedContext.currentPresentationData.with { $0 } let actionSheet = ActionSheetController(presentationData: presentationData) actionSheet.setItemGroups([ActionSheetItemGroup(items: [ - //ActionSheetTextItem(title: presentationData.strings.AutoDownloadSettings_ResetHelp), - ActionSheetButtonItem(title: "Delete All Exceptions", color: .destructive, action: { [weak actionSheet] in + ActionSheetButtonItem(title: presentationData.strings.Autosave_DeleteAllExceptions, color: .destructive, action: { [weak actionSheet] in actionSheet?.dismissAnimated() let _ = updateMediaAutoSaveSettingsInteractively(account: context.account, { settings in @@ -674,28 +671,27 @@ func saveIncomingMediaController(context: AccountContext, scope: SaveIncomingMed let title: String switch scope { case let .peer(id): - //TODO:localize if let data = mediaAutoSaveSettings.exceptions.first(where: { $0.id == id }) { configuration = data.configuration } else { configuration = .default } - title = "Exception" + title = presentationData.strings.Autosave_Exception case .addPeer: configuration = state.pendingConfiguration - title = "Add Exception" + title = presentationData.strings.Autosave_AddException case let .peerType(peerType): exceptions = mediaAutoSaveSettings.exceptions switch peerType { case .privateChats: configuration = mediaAutoSaveSettings.configurations[.users] ?? .default - title = "Private Chats" + title = presentationData.strings.Notifications_PrivateChats case .groups: configuration = mediaAutoSaveSettings.configurations[.groups] ?? .default - title = "Groups" + title = presentationData.strings.Notifications_GroupChats case .channels: configuration = mediaAutoSaveSettings.configurations[.channels] ?? .default - title = "Channels" + title = presentationData.strings.Notifications_Channels } } diff --git a/submodules/ShareController/Sources/ShareController.swift b/submodules/ShareController/Sources/ShareController.swift index 6ace0d2ed5..f4a7240ef5 100644 --- a/submodules/ShareController/Sources/ShareController.swift +++ b/submodules/ShareController/Sources/ShareController.swift @@ -1743,7 +1743,6 @@ public func presentExternalShare(context: AccountContext, text: String, parentCo } private func restrictedSendingContentsText(peer: EnginePeer, presentationData: PresentationData) -> String { - //TODO:localize var itemList: [String] = [] let order: [TelegramChatBannedRightsFlags] = [ @@ -1771,21 +1770,21 @@ private func restrictedSendingContentsText(peer: EnginePeer, presentationData: P var title: String? switch right { case .banSendText: - title = "text messages" + title = presentationData.strings.Chat_SendAllowedContentTypeText case .banSendPhotos: - title = "photos" + title = presentationData.strings.Chat_SendAllowedContentTypePhoto case .banSendVideos: - title = "videos" + title = presentationData.strings.Chat_SendAllowedContentTypeVideo case .banSendVoice: - title = "voice messages" + title = presentationData.strings.Chat_SendAllowedContentTypeVoiceMessage case .banSendInstantVideos: - title = "video messages" + title = presentationData.strings.Chat_SendAllowedContentTypeVideoMessage case .banSendFiles: - title = "files" + title = presentationData.strings.Chat_SendAllowedContentTypeFile case .banSendMusic: - title = "music" + title = presentationData.strings.Chat_SendAllowedContentTypeMusic case .banSendStickers: - title = "Stickers & GIFs" + title = presentationData.strings.Chat_SendAllowedContentTypeSticker default: break } @@ -1795,19 +1794,27 @@ private func restrictedSendingContentsText(peer: EnginePeer, presentationData: P } if itemList.isEmpty { - return "Sending messages is disabled in \(peer.compactDisplayTitle)" + return presentationData.strings.Chat_SendNotAllowedPeerText(peer.compactDisplayTitle).string } var itemListString = "" - for i in 0 ..< itemList.count { - if i != 0 { - itemListString.append(", ") + + if #available(iOS 13.0, *) { + let listFormatter = ListFormatter() + listFormatter.locale = localeWithStrings(presentationData.strings) + if let value = listFormatter.string(from: itemList) { + itemListString = value } - if i == itemList.count - 1 && i != 0 { - itemListString.append("and ") - } - itemListString.append(itemList[i]) } - return "The admins of \(peer.compactDisplayTitle) group only allow to send \(itemListString)." + if itemListString.isEmpty { + for i in 0 ..< itemList.count { + if i != 0 { + itemListString.append(", ") + } + itemListString.append(itemList[i]) + } + } + + return presentationData.strings.Chat_SendAllowedContentPeerText(peer.compactDisplayTitle, itemListString).string } diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift index 705acf40d3..2deeaa2e96 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift @@ -619,8 +619,7 @@ private final class StickerPackContainer: ASDisplayNode { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - //TODO:localize - let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Your emoji status has been updated.", undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) + let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: presentationData.strings.EmojiStatus_AppliedText, undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) controller.present(undoController, in: .window(.root)) } let copyEmoji: (TelegramMediaFile) -> Void = { file in @@ -643,9 +642,8 @@ private final class StickerPackContainer: ASDisplayNode { } } - //TODO:localize if strongSelf.sendEmoji != nil { - menuItems.append(.action(ContextMenuActionItem(text: "Send Emoji", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_SendEmoji, icon: { theme in if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) { return generateImage(image.size, rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) @@ -663,8 +661,7 @@ private final class StickerPackContainer: ASDisplayNode { }))) } - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Set as Status", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_SetAsStatus, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Smile"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in f(.default) @@ -688,8 +685,7 @@ private final class StickerPackContainer: ASDisplayNode { } }))) - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Copy Emoji", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_CopyEmoji, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in copyEmoji(file) diff --git a/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift b/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift index f0e4658df6..9f6225e203 100644 --- a/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift +++ b/submodules/TelegramUI/Components/AvatarEditorScreen/Sources/AvatarEditorScreen.swift @@ -230,7 +230,11 @@ final class AvatarEditorScreenComponent: Component { private let emojiSearchDisposable = MetaDisposable() private let emojiSearchState = Promise(EmojiSearchState(result: nil, isSearching: false)) - private var emojiSearchStateValue: EmojiSearchState = EmojiSearchState(result: nil, isSearching: false) + private var emojiSearchStateValue = EmojiSearchState(result: nil, isSearching: false) { + didSet { + self.emojiSearchState.set(.single(self.emojiSearchStateValue)) + } + } private var scheduledEmojiContentAnimationHint: EmojiPagerContentComponent.ContentAnimation? diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift index 428c4b5d97..11d965be51 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift @@ -637,8 +637,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - //TODO:localize - let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Your emoji status has been updated.", undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) + let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: presentationData.strings.EmojiStatus_AppliedText, undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) strongSelf.currentUndoOverlayController = controller controllerInteraction.presentController(controller, nil) }, @@ -673,8 +672,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - //TODO:localize - let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Emoji copied to clipboard.", undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) + let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: presentationData.strings.EmojiPreview_CopyEmoji, undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) strongSelf.currentUndoOverlayController = controller controllerInteraction.presentController(controller, nil) } @@ -1488,9 +1486,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { if let stickerSearchResult = stickerSearchState.result { var stickerSearchResults: EmojiPagerContentComponent.EmptySearchResults? if !stickerSearchResult.groups.contains(where: { !$0.items.isEmpty }) { - //TODO:localize stickerSearchResults = EmojiPagerContentComponent.EmptySearchResults( - text: "No stickers found", + text: presentationData.strings.EmojiSearch_SearchStickersEmptyResult, iconFile: nil ) } @@ -2506,8 +2503,7 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior { } if let _ = strongSelf.chatPeerId { - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Send Emoji", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_SendEmoji, icon: { theme in if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) { return generateImage(image.size, rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) @@ -2524,8 +2520,7 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior { f(.default) }))) - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Set as Status", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_SetAsStatus, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Smile"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in f(.default) @@ -2549,8 +2544,7 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior { } }))) - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Copy Emoji", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_CopyEmoji, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in copyEmoji(file) diff --git a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusPreviewScreen.swift b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusPreviewScreen.swift index 87fc6550ae..b8505beb86 100644 --- a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusPreviewScreen.swift +++ b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusPreviewScreen.swift @@ -672,7 +672,6 @@ final class EmojiStatusPreviewScreenComponent: Component { } )))) } - //TODO:localize menuItems.append(AnyComponentWithIdentity(id: "Other", component: AnyComponent(ContextMenuActionItem( title: component.strings.EmojiStatusSetup_TimerOther, action: { [weak self] in diff --git a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift index 05e46109d8..6100057c76 100644 --- a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift +++ b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift @@ -276,7 +276,11 @@ public final class EmojiStatusSelectionController: ViewController { private let emojiSearchDisposable = MetaDisposable() private let emojiSearchState = Promise(EmojiSearchState(result: nil, isSearching: false)) - private var emojiSearchStateValue: EmojiSearchState = EmojiSearchState(result: nil, isSearching: false) + private var emojiSearchStateValue = EmojiSearchState(result: nil, isSearching: false) { + didSet { + self.emojiSearchState.set(.single(self.emojiSearchStateValue)) + } + } private var emptyResultEmojis: [TelegramMediaFile] = [] private var stableEmptyResultEmoji: TelegramMediaFile? diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index 71ef231a15..cf4d3d0a4e 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -6979,8 +6979,7 @@ public final class EmojiPagerContentComponent: Component { } else { itemGroupIndexById[groupId] = itemGroups.count - //TODO:localize - let title = "TRENDING EMOJI" + let title = context.sharedContext.currentPresentationData.with({ $0 }).strings.EmojiInput_TrendingEmoji itemGroups.append(ItemGroup(supergroupId: groupId, id: groupId, title: title, subtitle: nil, isPremiumLocked: false, isFeatured: false, collapsedLineCount: 0, isClearable: false, headerItem: nil, items: [resultItem])) } } @@ -7670,8 +7669,7 @@ public final class EmojiPagerContentComponent: Component { } else if isEmojiSelection { displaySearchWithPlaceholder = strings.EmojiSearch_SearchEmojiPlaceholder } else if isProfilePhotoEmojiSelection || isGroupPhotoEmojiSelection { - //TODO:localize - displaySearchWithPlaceholder = "Search" + displaySearchWithPlaceholder = strings.Common_Search } } diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift index 02be699e83..49c742c471 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiSearchContent.swift @@ -59,7 +59,11 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode private let emojiSearchDisposable = MetaDisposable() private let emojiSearchState = Promise(EmojiSearchState(result: nil, isSearching: false)) - private var emojiSearchStateValue: EmojiSearchState = EmojiSearchState(result: nil, isSearching: false) + private var emojiSearchStateValue = EmojiSearchState(result: nil, isSearching: false) { + didSet { + self.emojiSearchState.set(.single(self.emojiSearchStateValue)) + } + } private var immediateEmojiSearchState: EmojiSearchState = EmojiSearchState(result: nil, isSearching: false) private var dataDisposable: Disposable? @@ -106,13 +110,12 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode groupItems.append(resultItem) } - //TODO:localize self.itemGroups.append(EmojiPagerContentComponent.ItemGroup( supergroupId: AnyHashable(groupItem.info.id), groupId: AnyHashable(groupItem.info.id), title: groupItem.info.title, subtitle: nil, - actionButtonTitle: "Add \(groupItem.info.title)", + actionButtonTitle: self.presentationData.strings.EmojiInput_AddPack(groupItem.info.title).string, isFeatured: true, isPremiumLocked: !self.hasPremiumForInstallation, isEmbedded: false, @@ -413,7 +416,6 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode let params = Params(size: size, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, inputHeight: inputHeight, deviceMetrics: deviceMetrics) self.params = params - //TODO:localize var emojiContent = EmojiPagerContentComponent( id: "emoji", context: self.context, @@ -427,7 +429,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode itemContentUniqueId: EmojiPagerContentComponent.ContentId(id: "main", version: 0), searchState: .empty(hasResults: false), warpContentsOnEdges: false, - displaySearchWithPlaceholder: "Search Emoji", + displaySearchWithPlaceholder: self.presentationData.strings.EmojiSearch_SearchEmojiPlaceholder, searchCategories: nil, searchInitiallyHidden: false, searchAlwaysActive: true, diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboard.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboard.swift index 1f3e69607e..7da8aa9f96 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboard.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboard.swift @@ -377,8 +377,7 @@ public final class EntityKeyboardComponent: Component { strongSelf.reorderPacks(category: .masks, items: items) } )))) - //TODO:localize - contentIcons.append(PagerComponentContentIcon(id: "masks", imageName: "Chat/Input/Media/EntityInputMasksIcon", title: "Masks")) + contentIcons.append(PagerComponentContentIcon(id: "masks", imageName: "Chat/Input/Media/EntityInputMasksIcon", title: component.strings.EmojiInput_TabMasks)) if let _ = component.maskContent?.inputInteractionHolder.inputInteraction?.openStickerSettings { contentAccessoryRightButtons.append(AnyComponentWithIdentity(id: "masks", component: AnyComponent(Button( content: AnyComponent(BundleIconComponent( @@ -464,8 +463,7 @@ public final class EntityKeyboardComponent: Component { reorderItems: { _ in } ))))*/ - //TODO:localize - contentIcons.append(PagerComponentContentIcon(id: "gifs", imageName: "Chat/Input/Media/EntityInputGifsIcon", title: "GIFs")) + contentIcons.append(PagerComponentContentIcon(id: "gifs", imageName: "Chat/Input/Media/EntityInputGifsIcon", title: component.strings.EmojiInput_TabGifs)) } if let stickerContent = component.stickerContent { @@ -571,8 +569,7 @@ public final class EntityKeyboardComponent: Component { strongSelf.reorderPacks(category: .stickers, items: items) } )))) - //TODO:localize - contentIcons.append(PagerComponentContentIcon(id: "stickers", imageName: "Chat/Input/Media/EntityInputStickersIcon", title: "Stickers")) + contentIcons.append(PagerComponentContentIcon(id: "stickers", imageName: "Chat/Input/Media/EntityInputStickersIcon", title: component.strings.EmojiInput_TabStickers)) if let _ = component.stickerContent?.inputInteractionHolder.inputInteraction?.openStickerSettings { contentAccessoryRightButtons.append(AnyComponentWithIdentity(id: "stickers", component: AnyComponent(Button( content: AnyComponent(BundleIconComponent( @@ -671,8 +668,7 @@ public final class EntityKeyboardComponent: Component { strongSelf.reorderPacks(category: .emoji, items: items) } )))) - //TODO:localize - contentIcons.append(PagerComponentContentIcon(id: "emoji", imageName: "Chat/Input/Media/EntityInputEmojiIcon", title: "Emoji")) + contentIcons.append(PagerComponentContentIcon(id: "emoji", imageName: "Chat/Input/Media/EntityInputEmojiIcon", title: component.strings.EmojiInput_TabEmoji)) if let _ = deleteBackwards { contentAccessoryLeftButtons.append(AnyComponentWithIdentity(id: "emoji", component: AnyComponent(Button( content: AnyComponent(BundleIconComponent( diff --git a/submodules/TelegramUI/Components/StorageUsageScreen/Sources/DataCategoryItemCompoment.swift b/submodules/TelegramUI/Components/StorageUsageScreen/Sources/DataCategoryItemCompoment.swift index 9ad5dfb0c2..d9d6280419 100644 --- a/submodules/TelegramUI/Components/StorageUsageScreen/Sources/DataCategoryItemCompoment.swift +++ b/submodules/TelegramUI/Components/StorageUsageScreen/Sources/DataCategoryItemCompoment.swift @@ -169,10 +169,9 @@ private final class SubItemComponent: Component { ) availableWidth = max(1.0, availableWidth - titleValueSize.width - 4.0) - //TODO:localize let titleSize = self.title.update( transition: transition, - component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: component.isIncoming ? "Incoming" : "Outgoing", font: Font.regular(17.0), textColor: component.theme.list.itemPrimaryTextColor)))), + component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: component.isIncoming ? component.strings.DataUsage_MediaDirectionIncoming : component.strings.DataUsage_MediaDirectionOutgoing, font: Font.regular(17.0), textColor: component.theme.list.itemPrimaryTextColor)))), environment: {}, containerSize: CGSize(width: availableWidth, height: 100.0) ) diff --git a/submodules/TelegramUI/Components/StorageUsageScreen/Sources/DataUsageScreen.swift b/submodules/TelegramUI/Components/StorageUsageScreen/Sources/DataUsageScreen.swift index 0dfe11eb8b..b1f87a59a5 100644 --- a/submodules/TelegramUI/Components/StorageUsageScreen/Sources/DataUsageScreen.swift +++ b/submodules/TelegramUI/Components/StorageUsageScreen/Sources/DataUsageScreen.swift @@ -266,18 +266,17 @@ final class DataUsageScreenComponent: Component { case .music: return strings.StorageManagement_SectionMusic case .messages: - //TODO:localize - return "Messages" + return strings.StorageManagement_SectionMessages case .stickers: return strings.StorageManagement_SectionStickers case .voiceMessages: - return "Voice Messages" + return strings.StorageManagement_SectionVoiceMessages case .calls: - return "Calls" + return strings.StorageManagement_SectionCalls case .totalIn: - return "Data Received" + return strings.DataUsage_SectionTotalIncoming case .totalOut: - return "Data Sent" + return strings.DataUsage_SectionTotalOutgoing } } } @@ -809,17 +808,16 @@ final class DataUsageScreenComponent: Component { let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.freeTextColor) let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: environment.theme.list.freeTextColor) - //TODO:localize let timestampString: String if let allStats = self.allStats, allStats.resetTimestamp != 0 { let dateStringPlain = stringForFullDate(timestamp: allStats.resetTimestamp, strings: environment.strings, dateTimeFormat: PresentationDateTimeFormat()) switch self.selectedStats { case .all: - timestampString = "Your data usage since \(dateStringPlain)" + timestampString = environment.strings.DataUsage_InfoTotalUsageSinceTime(dateStringPlain).string case .mobile: - timestampString = "Your mobile data usage since \(dateStringPlain)" + timestampString = environment.strings.DataUsage_InfoMobileUsageSinceTime(dateStringPlain).string case .wifi: - timestampString = "Your Wi-Fi data usage since \(dateStringPlain)" + timestampString = environment.strings.DataUsage_InfoWifiUsageSinceTime(dateStringPlain).string } } else { timestampString = "" @@ -972,10 +970,9 @@ final class DataUsageScreenComponent: Component { contentHeight += categoriesSize.height contentHeight += 8.0 - //TODO:localize let categoriesDescriptionSize = self.categoriesDescriptionView.update( transition: transition, - component: AnyComponent(MultilineTextComponent(text: .markdown(text: "Tap on each section for detailed view.", attributes: MarkdownAttributes( + component: AnyComponent(MultilineTextComponent(text: .markdown(text: environment.strings.DataUsage_SectionsInfo, attributes: MarkdownAttributes( body: body, bold: bold, link: body, @@ -996,15 +993,14 @@ final class DataUsageScreenComponent: Component { contentHeight += categoriesDescriptionSize.height contentHeight += 40.0 - //TODO:localize let totalTitle: String switch self.selectedStats { case .all: - totalTitle = "TOTAL NETWORK USAGE" + totalTitle = environment.strings.DataUsage_SectionUsageTotal case .mobile: - totalTitle = "MOBILE NETWORK USAGE" + totalTitle = environment.strings.DataUsage_SectionUsageMobile case .wifi: - totalTitle = "WI-FI NETWORK USAGE" + totalTitle = environment.strings.DataUsage_SectionUsageWifi } let totalCategoriesTitleSize = self.totalCategoriesTitleView.update( transition: transition, @@ -1053,7 +1049,6 @@ final class DataUsageScreenComponent: Component { contentHeight += 40.0 var autoDownloadSettingsContentHeight: CGFloat = 0.0 - //TODO:localize let autoDownloadSettingsSize: CGSize if case .all = self.selectedStats, let autoDownloadSettingsComponentView = self.autoDownloadSettingsView.view { autoDownloadSettingsSize = autoDownloadSettingsComponentView.bounds.size @@ -1063,7 +1058,7 @@ final class DataUsageScreenComponent: Component { component: AnyComponent(StoragePeerTypeItemComponent( theme: environment.theme, iconName: self.selectedStats == .mobile ? "Settings/Menu/Cellular" : "Settings/Menu/WiFi", - title: "Auto-Download Settings", + title: environment.strings.DataUsage_AutoDownloadSettings, subtitle: stringForAutoDownloadSetting(strings: environment.strings, decimalSeparator: environment.dateTimeFormat.decimalSeparator, settings: self.mediaAutoDownloadSettings, isCellular: self.selectedStats == .mobile), value: "", hasNext: false, @@ -1215,9 +1210,8 @@ final class DataUsageScreenComponent: Component { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let actionSheet = ActionSheetController(presentationData: presentationData) - //TODO:localize actionSheet.setItemGroups([ActionSheetItemGroup(items: [ - ActionSheetButtonItem(title: "Reset Statistics", color: .destructive, action: { [weak self, weak actionSheet] in + ActionSheetButtonItem(title: presentationData.strings.NetworkUsageSettings_ResetStats, color: .destructive, action: { [weak self, weak actionSheet] in actionSheet?.dismissAnimated() self?.commitClear() diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 96c62b8f8a..70d2465c2c 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -18221,9 +18221,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } func restrictedSendingContentsText() -> String { - //TODO:localize guard let peer = self.presentationInterfaceState.renderedPeer?.peer else { - return "Sending messages is disabled in this chat" + return self.presentationData.strings.Chat_SendNotAllowedText } var itemList: [String] = [] @@ -18253,21 +18252,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var title: String? switch right { case .banSendText: - title = "text messages" + title = self.presentationData.strings.Chat_SendAllowedContentTypeText case .banSendPhotos: - title = "photos" + title = self.presentationData.strings.Chat_SendAllowedContentTypePhoto case .banSendVideos: - title = "videos" + title = self.presentationData.strings.Chat_SendAllowedContentTypeVideo case .banSendVoice: - title = "voice messages" + title = self.presentationData.strings.Chat_SendAllowedContentTypeVoiceMessage case .banSendInstantVideos: - title = "video messages" + title = self.presentationData.strings.Chat_SendAllowedContentTypeVideoMessage case .banSendFiles: - title = "files" + title = self.presentationData.strings.Chat_SendAllowedContentTypeFile case .banSendMusic: - title = "music" + title = self.presentationData.strings.Chat_SendAllowedContentTypeMusic case .banSendStickers: - title = "Stickers & GIFs" + title = self.presentationData.strings.Chat_SendAllowedContentTypeSticker default: break } @@ -18277,21 +18276,28 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if itemList.isEmpty { - return "Sending messages is disabled in this chat" + return self.presentationData.strings.Chat_SendNotAllowedText } var itemListString = "" - for i in 0 ..< itemList.count { - if i != 0 { - itemListString.append(", ") + if #available(iOS 13.0, *) { + let listFormatter = ListFormatter() + listFormatter.locale = localeWithStrings(presentationData.strings) + if let value = listFormatter.string(from: itemList) { + itemListString = value } - if i == itemList.count - 1 && i != 0 { - itemListString.append("and ") - } - itemListString.append(itemList[i]) } - return "The admins of this group only allow to send \(itemListString)." + if itemListString.isEmpty { + for i in 0 ..< itemList.count { + if i != 0 { + itemListString.append(", ") + } + itemListString.append(itemList[i]) + } + } + + return self.presentationData.strings.Chat_SendAllowedContentText(itemListString).string } } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 8e43fa2241..cf39be1715 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -1017,8 +1017,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }), in: .current)*/ }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) } else { - //TODO:localize - strongSelf.controllerInteraction.presentController(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, title: nil, text: "Invoice not found", actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil) + strongSelf.controllerInteraction.presentController(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Chat_ErrorInvoiceNotFound, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil) } case let .instantView(webpage, anchor): strongSelf.pushController(InstantPageController(context: strongSelf.context, webPage: webpage, sourceLocation: InstantPageSourceLocation(userLocation: .peer(strongSelf.peer.id), peerType: .channel), anchor: anchor)) diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index d856ff800d..5dc474aba7 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -932,7 +932,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { guard let controller = strongSelf.interfaceInteraction?.chatController() as? ChatControllerImpl else { return } - //TODO:localize controller.controllerInteraction?.displayUndo(.universal(animation: "premium_unlock", scale: 1.0, colors: ["__allcolors__": UIColor(white: 1.0, alpha: 1.0)], title: nil, text: controller.restrictedSendingContentsText(), customUndoText: nil)) } else { strongSelf.ensureFocused() @@ -1384,8 +1383,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } } else { if sendingTextDisabled { - //TODO:localize - placeholder = "Text not allowed" + placeholder = interfaceState.strings.Chat_PlaceholderTextNotAllowed } else { if let channel = peer as? TelegramChannel, case .group = channel.info, channel.hasPermission(.canBeAnonymous) { placeholder = interfaceState.strings.Conversation_InputTextAnonymousPlaceholder @@ -2865,8 +2863,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - //TODO:localize - let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: "Your emoji status has been updated.", undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) + let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, title: nil, text: presentationData.strings.EmojiStatus_AppliedText, undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) //strongSelf.currentUndoOverlayController = controller controller.controllerInteraction?.presentController(undoController, nil) } @@ -2890,8 +2887,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } } - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Send Emoji", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_SendEmoji, icon: { theme in if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) { return generateImage(image.size, rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) @@ -2908,8 +2904,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { f(.default) }))) - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Set as Status", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_SetAsStatus, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Smile"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in f(.default) @@ -2933,8 +2928,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } }))) - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Copy Emoji", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_CopyEmoji, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in copyEmoji(file) diff --git a/submodules/TelegramUI/Sources/EmojisChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/EmojisChatInputContextPanelNode.swift index 66f0a8880e..52d948db0f 100644 --- a/submodules/TelegramUI/Sources/EmojisChatInputContextPanelNode.swift +++ b/submodules/TelegramUI/Sources/EmojisChatInputContextPanelNode.swift @@ -342,8 +342,7 @@ final class EmojisChatInputContextPanelNode: ChatInputContextPanelNode { let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } - //TODO:localize - let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: self.context, file: file, title: nil, text: "Your emoji status has been updated.", undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) + let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: self.context, file: file, title: nil, text: presentationData.strings.EmojiStatus_AppliedText, undoText: nil, customAction: nil), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return false }) //strongSelf.currentUndoOverlayController = controller controller.controllerInteraction?.presentController(undoController, nil) } @@ -367,8 +366,7 @@ final class EmojisChatInputContextPanelNode: ChatInputContextPanelNode { } } - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Send Emoji", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_SendEmoji, icon: { theme in if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) { return generateImage(image.size, rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) @@ -385,8 +383,7 @@ final class EmojisChatInputContextPanelNode: ChatInputContextPanelNode { f(.default) }))) - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Set as Status", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_SetAsStatus, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Smile"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in f(.default) @@ -410,8 +407,7 @@ final class EmojisChatInputContextPanelNode: ChatInputContextPanelNode { } }))) - //TODO:localize - menuItems.append(.action(ContextMenuActionItem(text: "Copy Emoji", icon: { theme in + menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.EmojiPreview_CopyEmoji, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in copyEmoji(file) diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 6f60a515eb..5901b7c7bd 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -713,8 +713,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur navigationController.pushViewController(checkoutController) } } else { - //TODO:localize - present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: "Invoice not found", actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) + present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Chat_ErrorInvoiceNotFound, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } } } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index c220b6ec98..ce567f5da3 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -727,10 +727,9 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p interaction.openSettings(.rememberPassword) })) } else if settings.suggestPasswordSetup { - //TODO:localize - items[.phone]!.append(PeerInfoScreenInfoItem(id: 0, title: "Protect Your Account", text: .markdown("Set a password that will be required each time log in with this phone number."), linkAction: { _ in + items[.phone]!.append(PeerInfoScreenInfoItem(id: 0, title: presentationData.strings.Settings_SuggestSetupPasswordTitle, text: .markdown(presentationData.strings.Settings_SuggestSetupPasswordText), linkAction: { _ in })) - items[.phone]!.append(PeerInfoScreenActionItem(id: 2, text: "Set Additional Password", action: { + items[.phone]!.append(PeerInfoScreenActionItem(id: 2, text: presentationData.strings.Settings_SuggestSetupPasswordAction, action: { interaction.openSettings(.passwordSetup) })) }