Localization

This commit is contained in:
Ali 2023-07-16 19:32:01 +04:00
parent aa3ce6132d
commit 295ba9541b
35 changed files with 224 additions and 147 deletions

View File

@ -9411,6 +9411,9 @@ Sorry for the inconvenience.";
"StoryFeed.TooltipStoryLimitValue_any" = "%d stories"; "StoryFeed.TooltipStoryLimitValue_any" = "%d stories";
"StoryFeed.TooltipStoryLimit" = "You can't post more than **%@** stories in **24 hours**."; "StoryFeed.TooltipStoryLimit" = "You can't post more than **%@** stories in **24 hours**.";
"StoryFeed.MyStory" = "My Story";
"StoryFeed.MyUploading" = "Uploading...";
"MediaPicker.AddImage" = "Add Image"; "MediaPicker.AddImage" = "Add Image";
"Premium.Stories" = "Story Posting"; "Premium.Stories" = "Story Posting";
@ -9429,3 +9432,105 @@ Sorry for the inconvenience.";
"Settings.MyStories" = "My Stories"; "Settings.MyStories" = "My Stories";
"Settings.StoriesArchive" = "Stories Archive"; "Settings.StoriesArchive" = "Stories Archive";
"ArchiveSettings.Title" = "Archive Settings";
"ArchiveSettings.UnmutedChatsHeader" = "UNMUTED CHATS";
"ArchiveSettings.UnmutedChatsFooter" = "Keep archived chats in the Archive even if they are unmuted and get a new message.";
"ArchiveSettings.FolderChatsHeader" = "CHATS FROM FOLDERS";
"ArchiveSettings.FolderChatsFooter" = "Keep archived chats from folders in the Archive even if they are unmuted and get a new message.";
"ArchiveSettings.UnknownChatsHeader" = "NEW CHATS FROM UNKNOWN USERS";
"ArchiveSettings.UnknownChatsFooter" = "Automatically archive and mute new private chats, groups and channels from non-contacts.";
"ArchiveSettings.KeepArchived" = "Always Keep Archived";
"ArchiveSettings.TooltipPremiumRequired" = "This setting is available only to the subscribers of [Telegram Premium]().";
"NotificationSettings.Stories.ShowAll" = "Show All Notifications";
"NotificationSettings.Stories.ShowImportant" = "Show Important Notifications";
"NotificationSettings.Stories.ShowImportantFooter" = "Always on for top 5 contacts.";
"NotificationSettings.Stories.DisplayAuthorName" = "Display Author Name";
"NotificationSettings.Stories.AutomaticValue" = "%@ (automatic)";
"NotificationSettings.Stories.CompactShowName" = "Show name";
"NotificationSettings.Stories.CompactHideName" = "Hide name";
"Notifications.StoriesTitle" = "Stories";
"Message.Story" = "Story";
"Notification.Exceptions.StoriesHeader" = "STORY NOTIFICATIONS";
"Notification.Exceptions.StoriesDisplayAuthorName" = "DISPLAY AUTHOR NAME";
"StorageManagement.SectionStories" = "Stories";
"PeerInfo.PaneStories" = "Stories";
"Story.TooltipExpired" = "This story is no longer available";
"Chat.ReplyExpiredStory" = "Expired story";
"Chat.ReplyStory" = "Story";
"Chat.StoryMentionAction" = "View Story";
"StoryList.ContextSaveToGallery" = "Save to Gallery";
"StoryList.ContextShowArchive" = "Show Archive";
"StoryList.TooltipStoriesDeleted_1" = "1 story deleted.";
"StoryList.TooltipStoriesDeleted_any" = "%d stories deleted.";
"Story.TooltipSaving" = "Saving";
"Story.TooltipSaved" = "Saved";
"StoryList.SaveToProfile" = "Save to Profile";
"StoryList.TooltipStoriesSavedToProfile_1" = "Story saved to your profile";
"StoryList.TooltipStoriesSavedToProfile_any" = "%d stories saved to your profile.";
"StoryList.TooltipStoriesSavedToProfileText" = "Saved stories can be viewed by others on your profile until you remove them.";
"StoryList.TitleSaved" = "My Stories";
"StoryList.TitleArchive" = "Stories Archive";
"StoryList.SubtitleSelected_1" = "1 story selected";
"StoryList.SubtitleSelected_any" = "%d stories selected";
"StoryList.SubtitleSaved_1" = "1 saved story";
"StoryList.SubtitleSaved_any" = "%d saved stories";
"StoryList.SubtitleCount_1" = "1 story";
"StoryList.SubtitleCount_any" = "%d stories";
"StoryList.ArchiveDescription" = "Only you can see archived stories unless you choose to save them to your profile.";
"StoryList.SavedEmptyState.Title" = "No saved stories";
"StoryList.SavedEmptyState.Text" = "Open the Archive to select stories you\nwant to be displayed in your profile.";
"StoryList.ArchivedEmptyState.Title" = "No Archived Stories";
"StoryList.ArchivedEmptyState.Text" = "Upload a new story to view it here";
"StoryList.SavedEmptyAction" = "Open Archive";
"ArchiveInfo.Title" = "This is Your Archive";
"ArchiveInfo.TextKeepArchivedUnmuted" = "Archived chats will remain in the Archive when you receive a new message. [Tap to change >]()";
"ArchiveInfo.TextKeepArchivedDefault" = "When you receive a new message, muted chats will remain in the Archive, while unmuted chats will be moved to Chats. [Tap to change >]()";
"ArchiveInfo.ChatsTitle" = "Archived Chats";
"ArchiveInfo.ChatsText" = "Move any chat into your Archive and back by swiping on it.";
"ArchiveInfo.HideTitle" = "Hiding Archive";
"ArchiveInfo.HideText" = "Hide the Archive from your Main screen by swiping on it.";
"ArchiveInfo.StoriesTitle" = "Stories";
"ArchiveInfo.StoriesText" = "Archive Stories from your contacts separately from chats with them.";
"ArchiveInfo.CloseAction" = "Got it";
"Story.HeaderYourStory" = "Your story";
"Story.HeaderEdited" = "edited";
"Story.CaptionShowMore" = "Show more";
"Story.UnsupportedText" = "This story is not supported by\nyour version of Telegram.";
"Story.UnsupportedAction" = "Update Telegram";
"Story.ScreenshotBlockedTitle" = "Screenshot Blocked";
"Story.ScreenshotBlockedText" = "The story you tried to take a\nscreenshot of is protected from\ncopying by its creator.";
"Story.Footer.NoViews" = "No views";
"Story.Footer.Views_1" = "1 view";
"Story.Footer.Views_any" = "%d views";
"Story.Footer.Uploading" = "Uploading...";

View File

@ -2576,7 +2576,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
text = self.presentationData.strings.StoryFeed_TooltipPremiumPosting text = self.presentationData.strings.StoryFeed_TooltipPremiumPosting
} else if reachedCountLimit { } else if reachedCountLimit {
let valueText = self.presentationData.strings.StoryFeed_TooltipStoryLimitValue(Int32(storiesCountLimit)) let valueText = self.presentationData.strings.StoryFeed_TooltipStoryLimitValue(Int32(storiesCountLimit))
text = self.presentationData.strings.StoryFeed_TooltipStoryLimit text = self.presentationData.strings.StoryFeed_TooltipStoryLimit(valueText).string
} else { } else {
text = "" text = ""
} }

View File

@ -303,7 +303,7 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
messageText = strings.Conversation_StoryMentionTextOutgoing(peer.compactDisplayTitle).string messageText = strings.Conversation_StoryMentionTextOutgoing(peer.compactDisplayTitle).string
} }
} else { } else {
messageText = strongs.Notification_Story messageText = strings.Notification_Story
} }
default: default:
break break

View File

@ -68,7 +68,7 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con
"Bottom.Group 1.Fill 1": iconColor, "Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor, "EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor "Line.Group 1.Stroke 1": iconColor
], title: nil, text: presentationData.strings.StoryFeed.TooltipNotifyOn(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string, customUndoText: nil, timeout: nil), ], title: nil, text: presentationData.strings.StoryFeed_TooltipNotifyOn(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string, customUndoText: nil, timeout: nil),
elevatedLayout: false, elevatedLayout: false,
animateInAsReplacement: false, animateInAsReplacement: false,
action: { _ in return false } action: { _ in return false }
@ -82,7 +82,7 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con
"Bottom.Group 1.Fill 1": iconColor, "Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor, "EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor "Line.Group 1.Stroke 1": iconColor
], title: nil, text: presentationData.strings.StoryFeed.TooltipNotifyOff(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)), customUndoText: nil, timeout: nil), ], title: nil, text: presentationData.strings.StoryFeed_TooltipNotifyOff(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string, customUndoText: nil, timeout: nil),
elevatedLayout: false, elevatedLayout: false,
animateInAsReplacement: false, animateInAsReplacement: false,
action: { _ in return false } action: { _ in return false }

View File

@ -391,7 +391,6 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis
} }
if addHeader { if addHeader {
//TODO:localize
commonHeader = ChatListSearchItemHeader(type: .text(strings.Contacts_SortedByPresence.uppercased(), AnyHashable(1)), theme: theme, strings: strings, actionTitle: nil, action: nil) commonHeader = ChatListSearchItemHeader(type: .text(strings.Contacts_SortedByPresence.uppercased(), AnyHashable(1)), theme: theme, strings: strings, actionTitle: nil, action: nil)
} }

View File

@ -1265,6 +1265,7 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
transition: indicatorTransition, transition: indicatorTransition,
component: AnyComponent(StorySetIndicatorComponent( component: AnyComponent(StorySetIndicatorComponent(
context: self.context, context: self.context,
strings: self.context.sharedContext.currentPresentationData.with({ $0 }).strings,
peer: storyParams.peer, peer: storyParams.peer,
items: storyParams.items, items: storyParams.items,
hasUnseen: storyParams.hasUnseen, hasUnseen: storyParams.hasUnseen,

View File

@ -85,34 +85,33 @@ private enum ArchiveSettingsControllerEntry: ItemListNodeEntry {
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! ArchiveSettingsControllerArguments let arguments = arguments as! ArchiveSettingsControllerArguments
//TODO:localize
switch self { switch self {
case .unmutedHeader: case .unmutedHeader:
return ItemListSectionHeaderItem(presentationData: presentationData, text: "UNMUTED CHATS", sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: presentationData.strings.ArchiveSettings_UnmutedChatsHeader, sectionId: self.section)
case let .unmutedValue(value): case let .unmutedValue(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Always Keep Archived", value: value, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: presentationData.strings.ArchiveSettings_KeepArchived, value: value, sectionId: self.section, style: .blocks, updated: { value in
arguments.updateUnmuted(value) arguments.updateUnmuted(value)
}) })
case .unmutedFooter: case .unmutedFooter:
return ItemListTextItem(presentationData: presentationData, text: .markdown("Keep archived chats in the Archive even if they are unmuted and get a new message."), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .markdown(presentationData.strings.ArchiveSettings_UnmutedChatsFooter), sectionId: self.section)
case .foldersHeader: case .foldersHeader:
return ItemListSectionHeaderItem(presentationData: presentationData, text: "CHATS FROM FOLDERS", sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: presentationData.strings.ArchiveSettings_FolderChatsHeader, sectionId: self.section)
case let .foldersValue(value): case let .foldersValue(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Always Keep Archived", value: value, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: presentationData.strings.ArchiveSettings_KeepArchived, value: value, sectionId: self.section, style: .blocks, updated: { value in
arguments.updateFolders(value) arguments.updateFolders(value)
}) })
case .foldersFooter: case .foldersFooter:
return ItemListTextItem(presentationData: presentationData, text: .markdown("Keep archived chats from folders in the Archive even if they are unmuted and get a new message."), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .markdown(presentationData.strings.ArchiveSettings_FolderChatsFooter), sectionId: self.section)
case .unknownHeader: case .unknownHeader:
return ItemListSectionHeaderItem(presentationData: presentationData, text: "NEW CHATS FROM UNKNOWN USERS", sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: presentationData.strings.ArchiveSettings_UnknownChatsHeader, sectionId: self.section)
case let .unknownValue(isOn, isLocked): case let .unknownValue(isOn, isLocked):
return ItemListSwitchItem(presentationData: presentationData, title: "Always Keep Archived", value: isOn, enableInteractiveChanges: !isLocked, enabled: true, displayLocked: isLocked, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: presentationData.strings.ArchiveSettings_KeepArchived, value: isOn, enableInteractiveChanges: !isLocked, enabled: true, displayLocked: isLocked, sectionId: self.section, style: .blocks, updated: { value in
arguments.updateUnknown(value) arguments.updateUnknown(value)
}, activatedWhileDisabled: { }, activatedWhileDisabled: {
arguments.updateUnknown(nil) arguments.updateUnknown(nil)
}) })
case .unknownFooter: case .unknownFooter:
return ItemListTextItem(presentationData: presentationData, text: .markdown("Automatically archive and mute new private chats, groups and channels from non-contacts."), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .markdown(presentationData.strings.ArchiveSettings_UnknownChatsFooter), sectionId: self.section)
} }
} }
} }
@ -163,7 +162,8 @@ public func archiveSettingsController(context: AccountContext) -> ViewController
if let value { if let value {
let _ = context.engine.privacy.updateAccountAutoArchiveChats(value: value).start() let _ = context.engine.privacy.updateAccountAutoArchiveChats(value: value).start()
} else { } else {
presentUndoImpl?(.premiumPaywall(title: nil, text: "This setting is available only to the subscribers of [Telegram Premium]().", customUndoText: nil, timeout: nil, linkAction: { _ in let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentUndoImpl?(.premiumPaywall(title: nil, text: presentationData.strings.ArchiveSettings_TooltipPremiumRequired, customUndoText: nil, timeout: nil, linkAction: { _ in
presentPremiumImpl?() presentPremiumImpl?()
})) }))
} }
@ -181,8 +181,7 @@ public func archiveSettingsController(context: AccountContext) -> ViewController
let isPremium = accountPeer?.isPremium ?? false let isPremium = accountPeer?.isPremium ?? false
let isPremiumDisabled = PremiumConfiguration.with(appConfiguration: appConfiguration).isPremiumDisabled let isPremiumDisabled = PremiumConfiguration.with(appConfiguration: appConfiguration).isPremiumDisabled
//TODO:localize let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.ArchiveSettings_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Archive Settings"), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: archiveSettingsControllerEntries( let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: archiveSettingsControllerEntries(
presentationData: presentationData, presentationData: presentationData,
settings: settings, settings: settings,

View File

@ -345,17 +345,16 @@ private func notificationsPeerCategoryEntries(category: NotificationsPeerCategor
importantEnabled = true importantEnabled = true
} }
//TODO:localize entries.append(.enable(presentationData.theme, presentationData.strings.NotificationSettings_Stories_ShowAll, allEnabled))
entries.append(.enable(presentationData.theme, "Show All Notifications", allEnabled))
if !allEnabled { if !allEnabled {
entries.append(.enableImportant(presentationData.theme, "Show Important Notifications", importantEnabled)) entries.append(.enableImportant(presentationData.theme, presentationData.strings.NotificationSettings_Stories_ShowImportant, importantEnabled))
entries.append(.importantInfo(presentationData.theme, "Always on for top 5 contacts.")) entries.append(.importantInfo(presentationData.theme, presentationData.strings.NotificationSettings_Stories_ShowImportantFooter))
} }
if notificationSettings.enabled || !notificationExceptions.isEmpty { if notificationSettings.enabled || !notificationExceptions.isEmpty {
entries.append(.optionsHeader(presentationData.theme, presentationData.strings.Notifications_Options.uppercased())) entries.append(.optionsHeader(presentationData.theme, presentationData.strings.Notifications_Options.uppercased()))
entries.append(.previews(presentationData.theme, "Display Author Name", notificationSettings.storySettings.hideSender != .hide)) entries.append(.previews(presentationData.theme, presentationData.strings.NotificationSettings_Stories_DisplayAuthorName, notificationSettings.storySettings.hideSender != .hide))
entries.append(.sound(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsSound, localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: filteredGlobalSound(notificationSettings.storySettings.sound)), filteredGlobalSound(notificationSettings.storySettings.sound))) entries.append(.sound(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsSound, localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: filteredGlobalSound(notificationSettings.storySettings.sound)), filteredGlobalSound(notificationSettings.storySettings.sound)))
} }
} else { } else {
@ -413,8 +412,7 @@ private func notificationsPeerCategoryEntries(category: NotificationsPeerCategor
var title: String = "" var title: String = ""
if automaticSet.contains(value.peer.id) { if automaticSet.contains(value.peer.id) {
//TODO:localize title = presentationData.strings.NotificationSettings_Stories_AutomaticValue(presentationData.strings.Notification_Exceptions_AlwaysOn).string
title = "\(presentationData.strings.Notification_Exceptions_AlwaysOn) (automatic)"
canRemove = false canRemove = false
} else { } else {
if case .stories = category { if case .stories = category {
@ -443,11 +441,10 @@ private func notificationsPeerCategoryEntries(category: NotificationsPeerCategor
if !title.isEmpty { if !title.isEmpty {
title += ", " title += ", "
} }
//TODO:localize
if case .show = value.settings.storySettings.hideSender { if case .show = value.settings.storySettings.hideSender {
title += "Show Name" title += presentationData.strings.NotificationSettings_Stories_CompactShowName
} else { } else {
title += "Hide Name" title += presentationData.strings.NotificationSettings_Stories_CompactHideName
} }
} }
} }
@ -1068,8 +1065,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor
case .channel: case .channel:
title = presentationData.strings.Notifications_ChannelsTitle title = presentationData.strings.Notifications_ChannelsTitle
case .stories: case .stories:
//TODO:localize title = presentationData.strings.Notifications_StoriesTitle
title = "Stories"
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: entries, style: .blocks, ensureVisibleItemTag: focusOnItemTag, initialScrollToItem: scrollToItem) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: entries, style: .blocks, ensureVisibleItemTag: focusOnItemTag, initialScrollToItem: scrollToItem)

View File

@ -396,8 +396,7 @@ public func stringForMediaKind(_ kind: MessageContentKind, strings: Presentation
case let .invoice(text): case let .invoice(text):
return (NSAttributedString(string: text), true) return (NSAttributedString(string: text), true)
case .story: case .story:
//TODO:localize return (NSAttributedString(string: strings.Message_Story), true)
return (NSAttributedString(string: "Story"), true)
} }
} }

View File

@ -283,7 +283,6 @@ public final class ChatListNavigationBar: Component {
placeholder = component.strings.Common_Search placeholder = component.strings.Common_Search
compactPlaceholder = component.strings.Common_Search compactPlaceholder = component.strings.Common_Search
//TODO:localize
searchContentNode = NavigationBarSearchContentNode( searchContentNode = NavigationBarSearchContentNode(
theme: component.theme, theme: component.theme,
placeholder: placeholder, placeholder: placeholder,

View File

@ -726,8 +726,7 @@ private func notificationPeerExceptionEntries(presentationData: PresentationData
if isStories == nil || isStories == true { if isStories == nil || isStories == true {
if case .user = peer { if case .user = peer {
//TODO:localize entries.append(.storyNotificationsHeader(index: index, theme: presentationData.theme, title: presentationData.strings.Notification_Exceptions_StoriesHeader))
entries.append(.storyNotificationsHeader(index: index, theme: presentationData.theme, title: "STORY NOTIFICATIONS"))
index += 1 index += 1
entries.append(.storyNotifications(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOn, selected: state.storiesMuted == .alwaysOn)) entries.append(.storyNotifications(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOn, selected: state.storiesMuted == .alwaysOn))
index += 1 index += 1
@ -735,7 +734,7 @@ private func notificationPeerExceptionEntries(presentationData: PresentationData
index += 1 index += 1
if state.storiesMuted != .alwaysOff { if state.storiesMuted != .alwaysOff {
entries.append(.displayPreviewsHeader(index: index, theme: presentationData.theme, title: "DISPLAY AUTHOR NAME")) entries.append(.displayPreviewsHeader(index: index, theme: presentationData.theme, title: presentationData.strings.Notification_Exceptions_StoriesDisplayAuthorName))
index += 1 index += 1
entries.append(.showSender(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOn, selected: state.storiesHideSender == .alwaysOn)) entries.append(.showSender(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOn, selected: state.storiesHideSender == .alwaysOn))
index += 1 index += 1

View File

@ -88,9 +88,7 @@ final class PeerInfoStoryGridScreenComponent: Component {
let strings = presentationData.strings let strings = presentationData.strings
if self.selectedCount != 0 { if self.selectedCount != 0 {
//TODO:localize items.append(.action(ContextMenuActionItem(text: presentationData.strings.StoryList_ContextSaveToGallery, icon: { theme in
//TODO:update icon
items.append(.action(ContextMenuActionItem(text: "Save to Photos", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in }, action: { [weak self] _, a in
a(.default) a(.default)
@ -113,16 +111,10 @@ final class PeerInfoStoryGridScreenComponent: Component {
return return
} }
let _ = component.context.engine.messages.deleteStories(ids: Array(paneNode.selectedIds)).start() let _ = component.context.engine.messages.deleteStories(ids: Array(paneNode.selectedIds)).start()
//TODO:localize
let text: String
if paneNode.selectedIds.count == 1 {
text = "1 story deleted."
} else {
text = "\(paneNode.selectedIds.count) stories deleted."
}
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme) let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
let text: String = presentationData.strings.StoryList_TooltipStoriesDeleted(Int32(paneNode.selectedIds.count))
environment.controller()?.present(UndoOverlayController( environment.controller()?.present(UndoOverlayController(
presentationData: presentationData, presentationData: presentationData,
content: .info(title: nil, text: text, timeout: nil), content: .info(title: nil, text: text, timeout: nil),
@ -163,8 +155,7 @@ final class PeerInfoStoryGridScreenComponent: Component {
if component.peerId == component.context.account.peerId, case .saved = component.scope { if component.peerId == component.context.account.peerId, case .saved = component.scope {
var ignoreNextActions = false var ignoreNextActions = false
//TODO:localize items.append(.action(ContextMenuActionItem(text: presentationData.strings.StoryList_ContextShowArchive, icon: { theme in
items.append(.action(ContextMenuActionItem(text: "Show Archive", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/StoryArchive"), color: theme.contextMenu.primaryColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/StoryArchive"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in }, action: { [weak self] _, a in
if ignoreNextActions { if ignoreNextActions {
@ -305,8 +296,8 @@ final class PeerInfoStoryGridScreenComponent: Component {
return return
} }
//TODO:localize let strings = (component.context.sharedContext.currentPresentationData.with { $0 }).strings
let saveScreen = SaveProgressScreen(context: component.context, content: .progress("Saving", 0.0)) let saveScreen = SaveProgressScreen(context: component.context, content: .progress(strings.Story_TooltipSaving, 0.0))
self.environment?.controller()?.present(saveScreen, in: .current) self.environment?.controller()?.present(saveScreen, in: .current)
let valueNorm: Float = 1.0 / Float(sortedItems.count) let valueNorm: Float = 1.0 / Float(sortedItems.count)
@ -330,12 +321,12 @@ final class PeerInfoStoryGridScreenComponent: Component {
guard let saveScreen else { guard let saveScreen else {
return return
} }
saveScreen.content = .progress("Saving", progress) saveScreen.content = .progress(strings.Story_TooltipSaving, progress)
}, completed: { [weak saveScreen] in }, completed: { [weak saveScreen] in
guard let saveScreen else { guard let saveScreen else {
return return
} }
saveScreen.content = .completion("Saved") saveScreen.content = .completion(strings.Story_TooltipSaved)
Queue.mainQueue().after(3.0, { [weak saveScreen] in Queue.mainQueue().after(3.0, { [weak saveScreen] in
saveScreen?.dismiss() saveScreen?.dismiss()
}) })
@ -376,12 +367,11 @@ final class PeerInfoStoryGridScreenComponent: Component {
self.selectionPanel = selectionPanel self.selectionPanel = selectionPanel
} }
//TODO:localize
let selectionPanelSize = selectionPanel.update( let selectionPanelSize = selectionPanel.update(
transition: selectionPanelTransition, transition: selectionPanelTransition,
component: AnyComponent(BottomButtonPanelComponent( component: AnyComponent(BottomButtonPanelComponent(
theme: environment.theme, theme: environment.theme,
title: "Save to Profile", title: environment.strings.StoryList_SaveToProfile,
label: nil, label: nil,
isEnabled: true, isEnabled: true,
insets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: environment.safeInsets.bottom, right: sideInset), insets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: environment.safeInsets.bottom, right: sideInset),
@ -395,18 +385,12 @@ final class PeerInfoStoryGridScreenComponent: Component {
let _ = component.context.engine.messages.updateStoriesArePinned(ids: paneNode.selectedItems, isPinned: true).start() let _ = component.context.engine.messages.updateStoriesArePinned(ids: paneNode.selectedItems, isPinned: true).start()
//TODO:localize
let title: String
if paneNode.selectedIds.count == 1 {
title = "Story saved to your profile"
} else {
title = "\(paneNode.selectedIds.count) saved to your profile"
}
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme) let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
let title: String = presentationData.strings.StoryList_TooltipStoriesSavedToProfile(Int32(paneNode.selectedIds.count))
environment.controller()?.present(UndoOverlayController( environment.controller()?.present(UndoOverlayController(
presentationData: presentationData, presentationData: presentationData,
content: .info(title: title, text: "Saved stories can be viewed by others on your profile until you remove them.", timeout: nil), content: .info(title: title, text: presentationData.strings.StoryList_TooltipStoriesSavedToProfileText, timeout: nil),
elevatedLayout: false, elevatedLayout: false,
animateInAsReplacement: false, animateInAsReplacement: false,
action: { _ in return false } action: { _ in return false }
@ -596,7 +580,8 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
} }
func updateTitle() { func updateTitle() {
//TODO:localize let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
switch self.scope { switch self.scope {
case .saved: case .saved:
guard let componentView = self.node.hostView.componentView as? PeerInfoStoryGridScreenComponent.View else { guard let componentView = self.node.hostView.componentView as? PeerInfoStoryGridScreenComponent.View else {
@ -608,16 +593,16 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
} else { } else {
title = nil title = nil
} }
self.titleView?.titleContent = .custom("My Stories", title, false) self.titleView?.titleContent = .custom(presentationData.strings.StoryList_TitleSaved, title, false)
case .archive: case .archive:
guard let componentView = self.node.hostView.componentView as? PeerInfoStoryGridScreenComponent.View else { guard let componentView = self.node.hostView.componentView as? PeerInfoStoryGridScreenComponent.View else {
return return
} }
let title: String let title: String
if componentView.selectedCount != 0 { if componentView.selectedCount != 0 {
title = "\(componentView.selectedCount) Selected" title = presentationData.strings.StoryList_SubtitleSelected(Int32(componentView.selectedCount))
} else { } else {
title = "Stories Archive" title = presentationData.strings.StoryList_TitleArchive
} }
self.titleView?.titleContent = .custom(title, nil, false) self.titleView?.titleContent = .custom(title, nil, false)
} }

View File

@ -1560,17 +1560,11 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
let title: String let title: String
if state.totalCount == 0 { if state.totalCount == 0 {
title = "" title = ""
} else if state.totalCount == 1 {
if self.isSaved {
title = "1 saved story"
} else {
title = "1 story"
}
} else { } else {
if self.isSaved { if self.isSaved {
title = "\(state.totalCount) saved stories" title = self.presentationData.strings.StoryList_SubtitleSaved(Int32(state.totalCount))
} else { } else {
title = "\(state.totalCount) stories" title = self.presentationData.strings.StoryList_SubtitleCount(Int32(state.totalCount))
} }
} }
self.statusPromise.set(.single(PeerInfoStatusData(text: title, isActivity: false, key: .stories))) self.statusPromise.set(.single(PeerInfoStatusData(text: title, isActivity: false, key: .stories)))
@ -1607,8 +1601,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
var headerText: String? var headerText: String?
if strongSelf.isArchive && !mappedItems.isEmpty { if strongSelf.isArchive && !mappedItems.isEmpty {
//TODO:localize headerText = strongSelf.presentationData.strings.StoryList_ArchiveDescription
headerText = "Only you can see archived stories unless you choose to save them to your profile."
} }
let items = SparseItemGrid.Items( let items = SparseItemGrid.Items(
@ -1914,16 +1907,15 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
emptyStateView = ComponentView() emptyStateView = ComponentView()
self.emptyStateView = emptyStateView self.emptyStateView = emptyStateView
} }
//TODO:localize
let emptyStateSize = emptyStateView.update( let emptyStateSize = emptyStateView.update(
transition: emptyStateTransition, transition: emptyStateTransition,
component: AnyComponent(EmptyStateIndicatorComponent( component: AnyComponent(EmptyStateIndicatorComponent(
context: self.context, context: self.context,
theme: presentationData.theme, theme: presentationData.theme,
animationName: "StoryListEmpty", animationName: "StoryListEmpty",
title: self.isArchive ? "No Archived Stories" : "No saved stories", title: self.isArchive ? presentationData.strings.StoryList_ArchivedEmptyState_Title : presentationData.strings.StoryList_SavedEmptyState_Title,
text: self.isArchive ? "Upload a new story to view it here" : "Open the Archive to select stories you\nwant to be displayed in your profile.", text: self.isArchive ? presentationData.strings.StoryList_ArchivedEmptyState_Text : presentationData.strings.StoryList_SavedEmptyState_Text,
actionTitle: self.isArchive ? nil : "Open Archive", actionTitle: self.isArchive ? nil : presentationData.strings.StoryList_SavedEmptyAction,
action: { [weak self] in action: { [weak self] in
guard let self else { guard let self else {
return return

View File

@ -128,12 +128,11 @@ public final class ArchiveInfoContentComponent: Component {
contentHeight += 15.0 contentHeight += 15.0
let titleString = NSMutableAttributedString() let titleString = NSMutableAttributedString()
titleString.append(NSAttributedString(string: "This is Your Archive", font: Font.semibold(19.0), textColor: component.theme.list.itemPrimaryTextColor)) titleString.append(NSAttributedString(string: component.strings.ArchiveInfo_Title, font: Font.semibold(19.0), textColor: component.theme.list.itemPrimaryTextColor))
let imageAttachment = NSTextAttachment() let imageAttachment = NSTextAttachment()
imageAttachment.image = self.iconBackground.image imageAttachment.image = self.iconBackground.image
titleString.append(NSAttributedString(attachment: imageAttachment)) titleString.append(NSAttributedString(attachment: imageAttachment))
//TODO:localize
let titleSize = self.title.update( let titleSize = self.title.update(
transition: .immediate, transition: .immediate,
component: AnyComponent(MultilineTextComponent( component: AnyComponent(MultilineTextComponent(
@ -153,11 +152,10 @@ public final class ArchiveInfoContentComponent: Component {
contentHeight += 16.0 contentHeight += 16.0
let text: String let text: String
//TODO:localize
if component.settings.keepArchivedUnmuted { if component.settings.keepArchivedUnmuted {
text = "Archived chats will remain in the Archive when you receive a new message. [Tap to change >]()" text = component.strings.ArchiveInfo_TextKeepArchivedUnmuted
} else { } else {
text = "When you receive a new message, muted chats will remain in the Archive, while unmuted chats will be moved to Chats. [Tap to change >]()" text = component.strings.ArchiveInfo_TextKeepArchivedDefault
} }
let mainText = NSMutableAttributedString() let mainText = NSMutableAttributedString()
@ -229,18 +227,18 @@ public final class ArchiveInfoContentComponent: Component {
let itemDescs: [ItemDesc] = [ let itemDescs: [ItemDesc] = [
ItemDesc( ItemDesc(
icon: "Chat List/Archive/IconArchived", icon: "Chat List/Archive/IconArchived",
title: "Archived Chats", title: component.strings.ArchiveInfo_ChatsTitle,
text: "Move any chat into your Archive and back by swiping on it." text: component.strings.ArchiveInfo_ChatsText
), ),
ItemDesc( ItemDesc(
icon: "Chat List/Archive/IconHide", icon: "Chat List/Archive/IconHide",
title: "Hiding Archive", title: component.strings.ArchiveInfo_HideTitle,
text: "Hide the Archive from your Main screen by swiping on it." text: component.strings.ArchiveInfo_HideText
), ),
ItemDesc( ItemDesc(
icon: "Chat List/Archive/IconStories", icon: "Chat List/Archive/IconStories",
title: "Stories", title: component.strings.ArchiveInfo_StoriesTitle,
text: "Archive Stories from your contacts separately from chats with them." text: component.strings.ArchiveInfo_StoriesText
) )
] ]
for i in 0 ..< itemDescs.count { for i in 0 ..< itemDescs.count {

View File

@ -76,7 +76,6 @@ private final class ArchiveInfoSheetContentComponent: Component {
contentHeight += contentSize.height contentHeight += contentSize.height
contentHeight += 30.0 contentHeight += 30.0
//TODO:localize
let buttonSize = self.button.update( let buttonSize = self.button.update(
transition: transition, transition: transition,
component: AnyComponent(ButtonComponent( component: AnyComponent(ButtonComponent(
@ -86,7 +85,7 @@ private final class ArchiveInfoSheetContentComponent: Component {
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8) pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
), ),
content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent( content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(
Text(text: "Got it", font: Font.semibold(17.0), color: environment.theme.list.itemCheckColors.foregroundColor) Text(text: environment.strings.ArchiveInfo_CloseAction, font: Font.semibold(17.0), color: environment.theme.list.itemCheckColors.foregroundColor)
)), )),
isEnabled: true, isEnabled: true,
displaysProgress: false, displaysProgress: false,

View File

@ -310,8 +310,7 @@ final class StorageUsageScreenComponent: Component {
case .misc: case .misc:
return strings.StorageManagement_SectionMiscellaneous return strings.StorageManagement_SectionMiscellaneous
case .stories: case .stories:
//TODO:localize return strings.StorageManagement_SectionStories
return "Stories"
} }
} }
@ -1810,8 +1809,7 @@ final class StorageUsageScreenComponent: Component {
mappedCategory = .groups mappedCategory = .groups
case 3: case 3:
iconName = "Settings/Menu/Stories" iconName = "Settings/Menu/Stories"
//TODO:localized title = environment.strings.Notifications_Stories
title = "Stories"
mappedCategory = .stories mappedCategory = .stories
default: default:
iconName = "Settings/Menu/Channels" iconName = "Settings/Menu/Channels"

View File

@ -6,6 +6,7 @@ import AccountContext
import TelegramCore import TelegramCore
import TelegramStringFormatting import TelegramStringFormatting
import MultilineTextComponent import MultilineTextComponent
import TelegramPresentationData
final class StoryAuthorInfoComponent: Component { final class StoryAuthorInfoComponent: Component {
struct Counters: Equatable { struct Counters: Equatable {
@ -14,13 +15,15 @@ final class StoryAuthorInfoComponent: Component {
} }
let context: AccountContext let context: AccountContext
let strings: PresentationStrings
let peer: EnginePeer? let peer: EnginePeer?
let timestamp: Int32 let timestamp: Int32
let counters: Counters? let counters: Counters?
let isEdited: Bool let isEdited: Bool
init(context: AccountContext, peer: EnginePeer?, timestamp: Int32, counters: Counters?, isEdited: Bool) { init(context: AccountContext, strings: PresentationStrings, peer: EnginePeer?, timestamp: Int32, counters: Counters?, isEdited: Bool) {
self.context = context self.context = context
self.strings = strings
self.peer = peer self.peer = peer
self.timestamp = timestamp self.timestamp = timestamp
self.counters = counters self.counters = counters
@ -31,6 +34,9 @@ final class StoryAuthorInfoComponent: Component {
if lhs.context !== rhs.context { if lhs.context !== rhs.context {
return false return false
} }
if lhs.strings !== rhs.strings {
return false
}
if lhs.peer != rhs.peer { if lhs.peer != rhs.peer {
return false return false
} }
@ -75,8 +81,7 @@ final class StoryAuthorInfoComponent: Component {
let title: String let title: String
if component.peer?.id == component.context.account.peerId { if component.peer?.id == component.context.account.peerId {
//TODO:localize title = component.strings.Story_HeaderYourStory
title = "Your story"
} else { } else {
title = component.peer?.debugDisplayTitle ?? "" title = component.peer?.debugDisplayTitle ?? ""
} }
@ -86,7 +91,7 @@ final class StoryAuthorInfoComponent: Component {
if component.isEdited { if component.isEdited {
subtitle.append("") subtitle.append("")
subtitle.append("edited") subtitle.append(component.strings.Story_HeaderEdited)
} }
let titleSize = self.title.update( let titleSize = self.title.update(

View File

@ -9,6 +9,7 @@ import TextNodeWithEntities
import TextFormat import TextFormat
import InvisibleInkDustNode import InvisibleInkDustNode
import UrlEscaping import UrlEscaping
import TelegramPresentationData
final class StoryContentCaptionComponent: Component { final class StoryContentCaptionComponent: Component {
enum Action { enum Action {
@ -41,6 +42,7 @@ final class StoryContentCaptionComponent: Component {
let externalState: ExternalState let externalState: ExternalState
let context: AccountContext let context: AccountContext
let strings: PresentationStrings
let text: String let text: String
let entities: [MessageTextEntity] let entities: [MessageTextEntity]
let entityFiles: [EngineMedia.Id: TelegramMediaFile] let entityFiles: [EngineMedia.Id: TelegramMediaFile]
@ -50,6 +52,7 @@ final class StoryContentCaptionComponent: Component {
init( init(
externalState: ExternalState, externalState: ExternalState,
context: AccountContext, context: AccountContext,
strings: PresentationStrings,
text: String, text: String,
entities: [MessageTextEntity], entities: [MessageTextEntity],
entityFiles: [EngineMedia.Id: TelegramMediaFile], entityFiles: [EngineMedia.Id: TelegramMediaFile],
@ -58,6 +61,7 @@ final class StoryContentCaptionComponent: Component {
) { ) {
self.externalState = externalState self.externalState = externalState
self.context = context self.context = context
self.strings = strings
self.text = text self.text = text
self.entities = entities self.entities = entities
self.entityFiles = entityFiles self.entityFiles = entityFiles
@ -72,6 +76,9 @@ final class StoryContentCaptionComponent: Component {
if lhs.context !== rhs.context { if lhs.context !== rhs.context {
return false return false
} }
if lhs.strings !== rhs.strings {
return false
}
if lhs.text != rhs.text { if lhs.text != rhs.text {
return false return false
} }
@ -425,9 +432,8 @@ final class StoryContentCaptionComponent: Component {
let truncationToken = NSMutableAttributedString() let truncationToken = NSMutableAttributedString()
truncationToken.append(NSAttributedString(string: "\u{2026} ", font: Font.regular(16.0), textColor: .white)) truncationToken.append(NSAttributedString(string: "\u{2026} ", font: Font.regular(16.0), textColor: .white))
truncationToken.append(NSAttributedString(string: "Show more", font: Font.semibold(16.0), textColor: .white)) truncationToken.append(NSAttributedString(string: component.strings.Story_CaptionShowMore, font: Font.semibold(16.0), textColor: .white))
//TODO:localize
let collapsedTextLayout = TextNodeWithEntities.asyncLayout(self.collapsedText.textNode)(TextNodeLayoutArguments( let collapsedTextLayout = TextNodeWithEntities.asyncLayout(self.collapsedText.textNode)(TextNodeLayoutArguments(
attributedString: attributedText, attributedString: attributedText,
maximumNumberOfLines: 3, maximumNumberOfLines: 3,

View File

@ -592,11 +592,10 @@ final class StoryItemContentComponent: Component {
self.unsupportedButton = unsupportedButton self.unsupportedButton = unsupportedButton
} }
//TODO:localize
let unsupportedTextSize = unsupportedText.update( let unsupportedTextSize = unsupportedText.update(
transition: .immediate, transition: .immediate,
component: AnyComponent(MultilineTextComponent( component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "This story is not supported by\nyour version of Telegram.", font: Font.regular(17.0), textColor: .white)), text: .plain(NSAttributedString(string: component.strings.Story_UnsupportedText, font: Font.regular(17.0), textColor: .white)),
horizontalAlignment: .center, horizontalAlignment: .center,
maximumNumberOfLines: 0 maximumNumberOfLines: 0
)), )),
@ -611,7 +610,7 @@ final class StoryItemContentComponent: Component {
foreground: environment.theme.list.itemCheckColors.foregroundColor, foreground: environment.theme.list.itemCheckColors.foregroundColor,
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.7) pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.7)
), ),
content: AnyComponentWithIdentity(id: AnyHashable(""), component: AnyComponent(Text(text: "Update Telegram", font: Font.semibold(17.0), color: environment.theme.list.itemCheckColors.foregroundColor content: AnyComponentWithIdentity(id: AnyHashable(""), component: AnyComponent(Text(text: component.strings.Story_UnsupportedAction, font: Font.semibold(17.0), color: environment.theme.list.itemCheckColors.foregroundColor
))), ))),
isEnabled: true, isEnabled: true,
displaysProgress: false, displaysProgress: false,
@ -655,7 +654,10 @@ final class StoryItemContentComponent: Component {
self.updateProgressMode(update: false) self.updateProgressMode(update: false)
if reloadMedia && synchronousLoad { if reloadMedia && synchronousLoad {
let _ = startTime
#if DEBUG
print("\(CFAbsoluteTimeGetCurrent()) Synchronous: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms") print("\(CFAbsoluteTimeGetCurrent()) Synchronous: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms")
#endif
} }
if !self.contentLoaded { if !self.contentLoaded {

View File

@ -34,11 +34,6 @@ final class StoryItemImageView: UIView {
super.init(frame: frame) super.init(frame: frame)
self.addSubview(self.contentView) self.addSubview(self.contentView)
#if DEBUG
if "".isEmpty {
self.contentView.isHidden = true
}
#endif
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
@ -292,11 +287,10 @@ final class CaptureProtectedInfoComponent: Component {
environment: {}, environment: {},
containerSize: availableSize containerSize: availableSize
) )
//TODO:localize
let titleSize = self.title.update( let titleSize = self.title.update(
transition: transition, transition: transition,
component: AnyComponent(MultilineTextComponent( component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "Screenshot Blocked", font: Font.semibold(20.0), textColor: .white)), text: .plain(NSAttributedString(string: component.strings.Story_ScreenshotBlockedTitle, font: Font.semibold(20.0), textColor: .white)),
horizontalAlignment: .center, horizontalAlignment: .center,
maximumNumberOfLines: 0 maximumNumberOfLines: 0
)), )),
@ -306,7 +300,7 @@ final class CaptureProtectedInfoComponent: Component {
let textSize = self.text.update( let textSize = self.text.update(
transition: transition, transition: transition,
component: AnyComponent(MultilineTextComponent( component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "The story you tried to take a\nscreenshot of is protected from\ncopying by its creator.", font: Font.regular(17.0), textColor: UIColor(white: 1.0, alpha: 0.6))), text: .plain(NSAttributedString(string: component.strings.Story_ScreenshotBlockedText, font: Font.regular(17.0), textColor: UIColor(white: 1.0, alpha: 0.6))),
horizontalAlignment: .center, horizontalAlignment: .center,
maximumNumberOfLines: 0 maximumNumberOfLines: 0
)), )),

View File

@ -2541,6 +2541,7 @@ public final class StoryItemSetContainerComponent: Component {
let centerInfoComponent = AnyComponent(StoryAuthorInfoComponent( let centerInfoComponent = AnyComponent(StoryAuthorInfoComponent(
context: component.context, context: component.context,
strings: component.strings,
peer: component.slice.peer, peer: component.slice.peer,
timestamp: component.slice.item.storyItem.timestamp, timestamp: component.slice.item.storyItem.timestamp,
counters: counters, counters: counters,
@ -2679,6 +2680,7 @@ public final class StoryItemSetContainerComponent: Component {
component: AnyComponent(StoryContentCaptionComponent( component: AnyComponent(StoryContentCaptionComponent(
externalState: captionItem.externalState, externalState: captionItem.externalState,
context: component.context, context: component.context,
strings: component.strings,
text: component.slice.item.storyItem.text, text: component.slice.item.storyItem.text,
entities: component.slice.item.storyItem.entities, entities: component.slice.item.storyItem.entities,
entityFiles: component.slice.item.entityFiles, entityFiles: component.slice.item.entityFiles,

View File

@ -685,6 +685,7 @@ final class StoryItemSetViewListComponent: Component {
transition: transition, transition: transition,
component: AnyComponent(StoryFooterPanelComponent( component: AnyComponent(StoryFooterPanelComponent(
context: component.context, context: component.context,
strings: component.strings,
storyItem: component.storyItem, storyItem: component.storyItem,
externalViews: externalViews, externalViews: externalViews,
expandFraction: dismissFraction, expandFraction: dismissFraction,

View File

@ -10,9 +10,11 @@ import TelegramCore
import MoreHeaderButton import MoreHeaderButton
import SemanticStatusNode import SemanticStatusNode
import SwiftSignalKit import SwiftSignalKit
import TelegramPresentationData
public final class StoryFooterPanelComponent: Component { public final class StoryFooterPanelComponent: Component {
public let context: AccountContext public let context: AccountContext
public let strings: PresentationStrings
public let storyItem: EngineStoryItem? public let storyItem: EngineStoryItem?
public let externalViews: EngineStoryItem.Views? public let externalViews: EngineStoryItem.Views?
public let expandFraction: CGFloat public let expandFraction: CGFloat
@ -22,6 +24,7 @@ public final class StoryFooterPanelComponent: Component {
public init( public init(
context: AccountContext, context: AccountContext,
strings: PresentationStrings,
storyItem: EngineStoryItem?, storyItem: EngineStoryItem?,
externalViews: EngineStoryItem.Views?, externalViews: EngineStoryItem.Views?,
expandFraction: CGFloat, expandFraction: CGFloat,
@ -30,6 +33,7 @@ public final class StoryFooterPanelComponent: Component {
moreAction: @escaping (UIView, ContextGesture?) -> Void moreAction: @escaping (UIView, ContextGesture?) -> Void
) { ) {
self.context = context self.context = context
self.strings = strings
self.storyItem = storyItem self.storyItem = storyItem
self.externalViews = externalViews self.externalViews = externalViews
self.expandViewStats = expandViewStats self.expandViewStats = expandViewStats
@ -42,6 +46,9 @@ public final class StoryFooterPanelComponent: Component {
if lhs.context !== rhs.context { if lhs.context !== rhs.context {
return false return false
} }
if lhs.strings !== rhs.strings {
return false
}
if lhs.storyItem != rhs.storyItem { if lhs.storyItem != rhs.storyItem {
return false return false
} }
@ -200,10 +207,9 @@ public final class StoryFooterPanelComponent: Component {
statusNode.transitionToState(.progress(value: CGFloat(max(0.08, self.uploadProgress)), cancelEnabled: true, appearance: SemanticStatusNodeState.ProgressAppearance(inset: 0.0, lineWidth: 2.0))) statusNode.transitionToState(.progress(value: CGFloat(max(0.08, self.uploadProgress)), cancelEnabled: true, appearance: SemanticStatusNodeState.ProgressAppearance(inset: 0.0, lineWidth: 2.0)))
//TODO:localize
let uploadingTextSize = uploadingText.update( let uploadingTextSize = uploadingText.update(
transition: .immediate, transition: .immediate,
component: AnyComponent(Text(text: "Uploading...", font: Font.regular(15.0), color: .white)), component: AnyComponent(Text(text: component.strings.Story_Footer_Uploading, font: Font.regular(15.0), color: .white)),
environment: {}, environment: {},
containerSize: CGSize(width: 200.0, height: 100.0) containerSize: CGSize(width: 200.0, height: 100.0)
) )
@ -260,11 +266,9 @@ public final class StoryFooterPanelComponent: Component {
let viewsText: String let viewsText: String
if viewCount == 0 { if viewCount == 0 {
viewsText = "No Views" viewsText = component.strings.Story_Footer_NoViews
} else if viewCount == 1 {
viewsText = "1 view"
} else { } else {
viewsText = "\(viewCount) views" viewsText = component.strings.Story_Footer_Views(Int32(viewCount))
} }
self.viewStatsButton.isEnabled = viewCount != 0 self.viewStatsButton.isEnabled = viewCount != 0

View File

@ -778,13 +778,12 @@ public final class StoryPeerListItemComponent: Component {
Transition.immediate.setShapeLayerPath(layer: self.indicatorShapeSeenLayer, path: calculateMergingCircleShape(center: indicatorCenter, leftCenter: mappedLeftCenter, rightCenter: mappedRightCenter, radius: indicatorRadius - indicatorLineUnseenWidth * 0.5, totalCount: component.totalCount, unseenCount: component.unseenCount, isSeen: true, segmentFraction: component.expandedAlphaFraction)) Transition.immediate.setShapeLayerPath(layer: self.indicatorShapeSeenLayer, path: calculateMergingCircleShape(center: indicatorCenter, leftCenter: mappedLeftCenter, rightCenter: mappedRightCenter, radius: indicatorRadius - indicatorLineUnseenWidth * 0.5, totalCount: component.totalCount, unseenCount: component.unseenCount, isSeen: true, segmentFraction: component.expandedAlphaFraction))
Transition.immediate.setShapeLayerPath(layer: self.indicatorShapeUnseenLayer, path: calculateMergingCircleShape(center: indicatorCenter, leftCenter: mappedLeftCenter, rightCenter: mappedRightCenter, radius: indicatorRadius - indicatorLineUnseenWidth * 0.5, totalCount: component.totalCount, unseenCount: component.unseenCount, isSeen: false, segmentFraction: component.expandedAlphaFraction)) Transition.immediate.setShapeLayerPath(layer: self.indicatorShapeUnseenLayer, path: calculateMergingCircleShape(center: indicatorCenter, leftCenter: mappedLeftCenter, rightCenter: mappedRightCenter, radius: indicatorRadius - indicatorLineUnseenWidth * 0.5, totalCount: component.totalCount, unseenCount: component.unseenCount, isSeen: false, segmentFraction: component.expandedAlphaFraction))
//TODO:localize
let titleString: String let titleString: String
if component.peer.id == component.context.account.peerId { if component.peer.id == component.context.account.peerId {
if let ringAnimation = component.ringAnimation, case .progress = ringAnimation { if let ringAnimation = component.ringAnimation, case .progress = ringAnimation {
titleString = "Uploading..." titleString = component.strings.StoryFeed_MyUploading
} else { } else {
titleString = "My story" titleString = component.strings.StoryFeed_MyStory
} }
} else { } else {
titleString = component.peer.compactDisplayTitle.trimmingCharacters(in: .whitespacesAndNewlines) titleString = component.peer.compactDisplayTitle.trimmingCharacters(in: .whitespacesAndNewlines)

View File

@ -89,6 +89,7 @@ private final class ShapeImageView: UIView {
public final class StorySetIndicatorComponent: Component { public final class StorySetIndicatorComponent: Component {
public let context: AccountContext public let context: AccountContext
public let strings: PresentationStrings
public let peer: EnginePeer public let peer: EnginePeer
public let items: [EngineStoryItem] public let items: [EngineStoryItem]
public let hasUnseen: Bool public let hasUnseen: Bool
@ -99,6 +100,7 @@ public final class StorySetIndicatorComponent: Component {
public init( public init(
context: AccountContext, context: AccountContext,
strings: PresentationStrings,
peer: EnginePeer, peer: EnginePeer,
items: [EngineStoryItem], items: [EngineStoryItem],
hasUnseen: Bool, hasUnseen: Bool,
@ -108,6 +110,7 @@ public final class StorySetIndicatorComponent: Component {
action: @escaping () -> Void action: @escaping () -> Void
) { ) {
self.context = context self.context = context
self.strings = strings
self.peer = peer self.peer = peer
self.items = items self.items = items
self.hasUnseen = hasUnseen self.hasUnseen = hasUnseen
@ -118,6 +121,9 @@ public final class StorySetIndicatorComponent: Component {
} }
public static func ==(lhs: StorySetIndicatorComponent, rhs: StorySetIndicatorComponent) -> Bool { public static func ==(lhs: StorySetIndicatorComponent, rhs: StorySetIndicatorComponent) -> Bool {
if lhs.strings !== rhs.strings {
return false
}
if lhs.items != rhs.items { if lhs.items != rhs.items {
return false return false
} }
@ -378,14 +384,11 @@ public final class StorySetIndicatorComponent: Component {
self.imageView.setNeedsDisplay() self.imageView.setNeedsDisplay()
} }
//TODO:localize
let textValue: String let textValue: String
if component.totalCount == 0 { if component.totalCount == 0 {
textValue = "" textValue = ""
} else if component.totalCount == 1 {
textValue = "1 story"
} else { } else {
textValue = "\(component.totalCount) stories" textValue = component.strings.Story_Footer_Views(Int32(component.totalCount))
} }
let textSize = self.text.update( let textSize = self.text.update(
transition: .immediate, transition: .immediate,

View File

@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "smoothGradient 0.4.png", "filename" : "smoothGradient 0.6.png",
"idiom" : "universal" "idiom" : "universal"
} }
], ],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -4524,8 +4524,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return return
} }
if let story = message.associatedStories[storyId], story.data.isEmpty { if let story = message.associatedStories[storyId], story.data.isEmpty {
//TODO:localize self.present(UndoOverlayController(presentationData: self.presentationData, content: .info(title: nil, text: self.presentationData.strings.Story_TooltipExpired, timeout: nil), elevatedLayout: false, action: { _ in return true }), in: .current)
self.present(UndoOverlayController(presentationData: self.presentationData, content: .info(title: nil, text: "This story is no longer available", timeout: nil), elevatedLayout: false, action: { _ in return true }), in: .current)
return return
} }

View File

@ -137,15 +137,14 @@ public class ChatMessageReplyInfoNode: ASDisplayNode {
} else { } else {
titleString = arguments.strings.User_DeletedAccount titleString = arguments.strings.User_DeletedAccount
} }
//TODO:localize
isText = false isText = false
if let storyItem = arguments.parentMessage.associatedStories[story], storyItem.data.isEmpty { if let storyItem = arguments.parentMessage.associatedStories[story], storyItem.data.isEmpty {
isExpiredStory = true isExpiredStory = true
textString = NSAttributedString(string: "Expired story") textString = NSAttributedString(string: arguments.strings.Chat_ReplyExpiredStory)
isMedia = false isMedia = false
} else { } else {
isStory = true isStory = true
textString = NSAttributedString(string: "Story") textString = NSAttributedString(string: arguments.strings.Chat_ReplyStory)
isMedia = true isMedia = true
} }
} else { } else {

View File

@ -194,9 +194,7 @@ class ChatMessageStoryMentionContentNode: ChatMessageBubbleContentNode {
let (subtitleLayout, subtitleApply) = makeSubtitleLayout(TextNodeLayoutArguments(attributedString: text, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) let (subtitleLayout, subtitleApply) = makeSubtitleLayout(TextNodeLayoutArguments(attributedString: text, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
//TODO:localize let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Chat_StoryMentionAction, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "View Story", font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
let backgroundSize = CGSize(width: width, height: subtitleLayout.size.height + 186.0) let backgroundSize = CGSize(width: width, height: subtitleLayout.size.height + 186.0)

View File

@ -833,12 +833,11 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
navigationController?.pushViewController(storyContainerScreen) navigationController?.pushViewController(storyContainerScreen)
}) })
} else { } else {
//TODO:localize
var elevatedLayout = true var elevatedLayout = true
if case .chat = urlContext { if case .chat = urlContext {
elevatedLayout = false elevatedLayout = false
} }
present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "story_expired", scale: 0.066, colors: [:], title: nil, text: "This story does not exist", customUndoText: nil, timeout: nil), elevatedLayout: elevatedLayout, animateInAsReplacement: false, action: { _ in present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "story_expired", scale: 0.066, colors: [:], title: nil, text: presentationData.strings.Story_TooltipExpired, customUndoText: nil, timeout: nil), elevatedLayout: elevatedLayout, animateInAsReplacement: false, action: { _ in
return true return true
}), nil) }), nil)
} }

View File

@ -956,8 +956,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
let title: String let title: String
switch key { switch key {
case .stories: case .stories:
//TODO:localize title = presentationData.strings.PeerInfo_PaneStories
title = "Stories"
case .media: case .media:
title = presentationData.strings.PeerInfo_PaneMedia title = presentationData.strings.PeerInfo_PaneMedia
case .files: case .files:

View File

@ -792,8 +792,7 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
} }
} }
//TODO:localize items[.stories]!.append(PeerInfoScreenDisclosureItem(id: 0, text: presentationData.strings.Settings_MyStories, icon: PresentationResourcesSettings.stories, action: {
items[.stories]!.append(PeerInfoScreenDisclosureItem(id: 0, text: "My Stories", icon: PresentationResourcesSettings.stories, action: {
interaction.openSettings(.stories) interaction.openSettings(.stories)
})) }))

View File

@ -141,8 +141,7 @@ final class WebpagePreviewAccessoryPanelNode: AccessoryPanelNode {
} else if content.type == "video" { } else if content.type == "video" {
text = stringForMediaKind(.video, strings: self.strings).0.string text = stringForMediaKind(.video, strings: self.strings).0.string
} else if content.type == "telegram_story" { } else if content.type == "telegram_story" {
//TODO:localize text = stringForMediaKind(.story, strings: self.strings).0.string
text = "Story"
} else if let _ = content.image { } else if let _ = content.image {
text = stringForMediaKind(.image, strings: self.strings).0.string text = stringForMediaKind(.image, strings: self.strings).0.string
} }