Update localization

This commit is contained in:
Isaac 2025-07-29 20:54:12 +02:00
parent 9e5b9d42c6
commit edd33a0103
15 changed files with 172 additions and 129 deletions

View File

@ -14787,3 +14787,82 @@ Sorry for the inconvenience.";
"Stars.SellGift.TonAmountTitle" = "PRICE IN TON";
"Stars.SellGift.OnlyTon" = "Only Accept TON";
"Stars.SellGift.OnlyTonInfo" = "If the buyer pays you in TON, there's no risk of refunds, unlike with Stars payments.";
"CallList.DeleteConfirmation" = "Do you want to delete the information about this call?";
"ChatList.Search.FilterGlobalPosts" = "Posts";
"ChatList.HeaderPublicPosts" = "PUBLIC POSTS";
"ChatList.PaidSearchToast.Text_1" = "%@ Star spent on extra search.";
"ChatList.PaidSearchToast.Text_any" = "%@ Stars spent on extra search.";
"ChatList.GlobalSearch.StartPlaceholder.Title" = "Global Search";
"ChatList.GlobalSearch.StartPlaceholder.Text" = "Type a keyword to search all posts\nfrom public channels.";
"ChatList.GlobalSearch.StartPlaceholder.Subtitle" = "Global search is a Premium feature.";
"ChatList.GlobalSearch.StartPlaceholder.RemainingSubtitle_1" = "%@ free search remaining today.";
"ChatList.GlobalSearch.StartPlaceholder.RemainingSubtitle_any" = "%@ free searches remaining today.";
"ChatList.GlobalSearch.LimitPlaceholder.Title" = "Limit Reached";
"ChatList.GlobalSearch.LimitPlaceholder.Text_1" = "You can make up to\n%@ search query per day.";
"ChatList.GlobalSearch.LimitPlaceholder.Text_any" = "You can make up to\n%@ search queries per day.";
"ChatList.GlobalSearch.SearchButton" = "Search";
"ChatList.GlobalSearch.SearchButtonPremium" = "Subscribe to Premium";
"ChatList.GlobalSearch.SearchButtonQuery" = "Search {}";
"ChatList.GlobalSearch.SearchButtonPaidTitle" = "Search for * %@";
"ChatList.GlobalSearch.SearchButtonPaidSubtitle" = "free search unlocks in %@";
"Chat.ViewCollection" = "VIEW COLLECTION";
"Chat.ViewAlbum" = "VIEW ALBUM";
"PeerInfo.MenuAddStories" = "Add Stories";
"Stories.MenuDeleteAlbum" = "Delete Album";
"Stories.AddStoriesTitle" = "Add Stories";
"Stories.AddStoriesEmpty" = "Add Stories";
"Stories.AddStories_1" = "Add %@ Story";
"Stories.AddStories_any" = "Add %@ Stories";
"Stories.MenuAddToAlbum" = "Add to Album";
"Stories.MenuRemoveFromAlbum" = "Remove from Album";
"Stories.MenuNewAlbum" = "New Album";
"Stories.MenuRenameAlbum" = "Rename Album";
"Stories.StatusEmpty" = "no stories";
"Stories.AlbumAll" = "All Stories";
"Stories.AlbumAdd" = "+ Add Album";
"Stories.AlbumEmptyTitle" = "Organize Your Stories";
"Stories.AlbumEmptyText" = "Add some stories to this album.";
"Stories.AlbumEmptyButton" = "Add to Album";
"Stories.CreateAlbum.Title" = "Create a New Album";
"Stories.CreateAlbum.Text" = "Choose a name for your album and start adding your stories there.";
"Stories.CreateAlbum.Placeholder" = "Title";
"Stories.EditAlbum.Title" = "Edit Album Name";
"Stories.EditAlbum.Text" = "Choose a new name for your album.";
"Stories.DeleteAlbum.Confirmation" = "Delete %@?";
"ProfileLevelInfo.Title" = "Rating";
"ProfileLevelInfo.MyText" = "The rating reflects your activity on Telegram. What affects it:";
"ProfileLevelInfo.MyDescriptionToday_1" = "The rating updates today.\n\%@ point is pending.";
"ProfileLevelInfo.MyDescriptionToday_any" = "The rating updates today.\n\%@ points are pending.";
"ProfileLevelInfo.MyDescriptionDays_1" = "%@ day";
"ProfileLevelInfo.MyDescriptionDays_any" = "%@ days";
"ProfileLevelInfo.MyDescriptionPoints_1" = "%@ point is";
"ProfileLevelInfo.MyDescriptionPoints_any" = "%@ points are";
"ProfileLevelInfo.MyDescription" = "The rating updates in %@ after purchases.\n\%@ pending.";
"ProfileLevelInfo.OtherDescription" = "The rating reflects **%@'s** activity on Telegram. What affects it:";
"ProfileLevelInfo.LevelIndex_1" = "Level %@";
"ProfileLevelInfo.LevelIndex_any" = "Level %@";
"ProfileLevelInfo.CloseButton" = "Understood";
"ProfileLevelInfo.Item0.Title" = "Gifts from Telegram";
"ProfileLevelInfo.Item0.Text" = "100% of the Stars spent on gifts purchased from Telegram.";
"ProfileLevelInfo.Item0.Badge" = "ADDED";
"ProfileLevelInfo.Item1.Title" = "Gifts and Posts from Users";
"ProfileLevelInfo.Item1.Text" = "20% of the Stars spent on gifts or posts from users and channels.";
"ProfileLevelInfo.Item1.Badge" = "ADDED";
"ProfileLevelInfo.Item2.Title" = "Refunds and Conversions";
"ProfileLevelInfo.Item2.Text" = "10x of refunded Stars and 85% of bought gifts converted to Stars.";
"ProfileLevelInfo.Item2.Badge" = "DEDUCTED";
"Call.AlertMoveToConference" = "End current call and start a conference?";
"Stories.Post.Album" = "Album";
"Stories.Post.AlbumFooter" = "Choose the albums where you want to share your story.";
"Stories.Post.AlbumAll" = "All Stories";
"Stories.Post.AlbumCount_1" = "%@ Album";
"Stories.Post.AlbumCount_any" = "%@ Albums";

View File

@ -350,8 +350,7 @@ final class CallListControllerNode: ASDisplayNode {
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
var items: [ActionSheetItem] = []
//TODO:localize
items.append(ActionSheetTextItem(title: "Do you want to delete the information about this call?", parseMarkdown: true))
items.append(ActionSheetTextItem(title: strongSelf.presentationData.strings.CallList_DeleteConfirmation, parseMarkdown: true))
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_DeleteMessagesFor(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()

View File

@ -93,9 +93,8 @@ private final class ItemNode: ASDisplayNode {
title = presentationData.strings.ChatList_Search_FilterApps
icon = nil
case .globalPosts:
//TODO:localize
title = "Posts"
titleBadge = "NEW"
title = presentationData.strings.ChatList_Search_FilterGlobalPosts
titleBadge = presentationData.strings.ChatList_ContextMenuBadgeNew
icon = nil
case .media:
title = presentationData.strings.ChatList_Search_FilterMedia

View File

@ -291,8 +291,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
}
}
} else if case .globalPosts = key {
//TODO:localize
header = ChatListSearchItemHeader(type: .text("Public Posts", 0), theme: theme, strings: strings, actionTitle: nil, action: nil)
header = ChatListSearchItemHeader(type: .text(strings.ChatList_HeaderPublicPosts, 0), theme: theme, strings: strings, actionTitle: nil, action: nil)
} else {
header = ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear, action: { _ in
clearRecentlySearchedPeers()
@ -1121,7 +1120,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
var headerType: ChatListSearchItemHeaderType = .messages(location: nil)
var actionTitle: String?
if key == .globalPosts {
headerType = .text("Public Posts", 0)
headerType = .text(presentationData.strings.ChatList_HeaderPublicPosts, 0)
} else {
if case let .forum(peerId) = location, let peer = peer.peer, peer.id == peerId {
headerType = .messages(location: peer.compactDisplayTitle)
@ -1138,8 +1137,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
case .privateChats:
filterTitle = presentationData.strings.ChatList_Search_Messages_PrivateChats
case .globalPosts:
//TODO:localize
filterTitle = "Public Posts"
filterTitle = presentationData.strings.ChatList_HeaderPublicPosts
}
actionTitle = "\(filterTitle) <"
}
@ -1230,14 +1228,13 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
case .privateChats:
filterTitle = presentationData.strings.ChatList_Search_Messages_PrivateChats
case .globalPosts:
filterTitle = "Public Posts"
filterTitle = presentationData.strings.ChatList_HeaderPublicPosts
}
actionTitle = "\(filterTitle) <"
let header: ChatListSearchItemHeader
if key == .globalPosts {
//TODO:localize
header = ChatListSearchItemHeader(type: .text("Public Posts", 0), theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
header = ChatListSearchItemHeader(type: .text(presentationData.strings.ChatList_HeaderPublicPosts, 0), theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
} else {
header = ChatListSearchItemHeader(type: .messages(location: nil), theme: presentationData.theme, strings: presentationData.strings, actionTitle: actionTitle, action: { sourceNode in
openMessagesFilter(sourceNode)
@ -1257,8 +1254,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
case .privateChats:
filterTitle = presentationData.strings.ChatList_Search_Messages_PrivateChats
case .globalPosts:
//TODO:localize
filterTitle = "Public Posts"
filterTitle = presentationData.strings.ChatList_HeaderPublicPosts
}
actionTitle = "\(filterTitle) <"
@ -5133,14 +5129,13 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
))
if let price {
//TODO:localize
if let controller = self.navigationController?.topViewController as? ViewController {
controller.present(UndoOverlayController(
presentationData: presentationData,
content: .starsSent(context: self.context, title: "", text: [AnimatedTextComponent.Item(
id: AnyHashable(0),
isUnbreakable: true,
content: .text("\(price) Stars spent on extra search.")
content: .text(presentationData.strings.ChatList_PaidSearchToast_Text(Int32(price)))
)], hasUndo: false),
elevatedLayout: false,
animateInAsReplacement: false,
@ -5400,9 +5395,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
if strongSelf.key == .globalPosts, let globalSearchStateValue = transition.globalSearchStateValue {
if !strongSelf.isPremium {
emptyResultsButtonContent = .premiumRequired
emptyResultsTitle = "Global Search"
emptyResultsText = "Type a keyword to search all posts\nfrom public channels."
emptyResultsButtonSubtitleText = "Global search is a Premium feature."
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Title
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Text
emptyResultsButtonSubtitleText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Subtitle
} else if let query = transition.query, !query.isEmpty {
if transition.approvedGlobalPostQueryState?.query == query {
emptyResultsButtonContent = nil
@ -5410,18 +5405,14 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
emptyResultsText = strongSelf.presentationData.strings.ChatList_Search_NoResultsQueryDescription(query).string
} else {
if globalSearchStateValue.remainingFreeSearches != 0 {
emptyResultsTitle = "Global Search"
emptyResultsText = "Type a keyword to search all posts\nfrom public channels."
if globalSearchStateValue.remainingFreeSearches == 1 {
emptyResultsButtonSubtitleText = "1 free search remaining today."
} else {
emptyResultsButtonSubtitleText = "\(globalSearchStateValue.remainingFreeSearches) free searches remaining today."
}
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Title
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Text
emptyResultsButtonSubtitleText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_RemainingSubtitle(Int32(globalSearchStateValue.remainingFreeSearches))
emptyResultsButtonContent = .searchQuery(query)
} else {
emptyResultsTitle = "Limit Reached"
emptyResultsText = "You can make up to\n\(globalSearchStateValue.totalFreeSearches) search queries per day."
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_LimitPlaceholder_Title
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_LimitPlaceholder_Text(Int32(globalSearchStateValue.totalFreeSearches))
emptyResultsButtonContent = .paidSearch(
price: Int(globalSearchStateValue.price.value),
@ -5432,17 +5423,12 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
} else {
if globalSearchStateValue.remainingFreeSearches != 0 {
emptyResultsButtonContent = .searchEmpty
emptyResultsTitle = "Global Search"
emptyResultsText = "Type a keyword to search all posts\nfrom public channels."
if globalSearchStateValue.remainingFreeSearches == 1 {
emptyResultsButtonSubtitleText = "1 free search remaining today."
} else {
emptyResultsButtonSubtitleText = "\(globalSearchStateValue.remainingFreeSearches) free searches remaining today."
}
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Title
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_Text
emptyResultsButtonSubtitleText = strongSelf.presentationData.strings.ChatList_GlobalSearch_StartPlaceholder_RemainingSubtitle(Int32(globalSearchStateValue.remainingFreeSearches))
} else {
emptyResultsTitle = "Limit Reached"
emptyResultsText = "You can make up to\n10 search queries per day."
emptyResultsTitle = strongSelf.presentationData.strings.ChatList_GlobalSearch_LimitPlaceholder_Title
emptyResultsText = strongSelf.presentationData.strings.ChatList_GlobalSearch_LimitPlaceholder_Text(Int32(globalSearchStateValue.totalFreeSearches))
emptyResultsButtonContent = .paidSearch(
price: Int(globalSearchStateValue.price.value),
@ -6228,10 +6214,20 @@ private final class EmptyResultsButtonSearchContent: Component {
containerSize: CGSize(width: 100.0, height: 100.0)
)
//TODO:localize
let string = NSMutableAttributedString()
string.append(NSAttributedString(string: "Search ", font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
string.append(NSAttributedString(string: component.query.trimmingCharacters(in: .whitespacesAndNewlines), font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor.withMultipliedAlpha(0.7)))
let rawString = component.strings.ChatList_GlobalSearch_SearchButtonQuery
if let range = rawString.range(of: "{}") {
if range.lowerBound != rawString.startIndex {
string.append(NSAttributedString(string: String(rawString[rawString.startIndex ..< range.lowerBound]), font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
}
string.append(NSAttributedString(string: component.query.trimmingCharacters(in: .whitespacesAndNewlines), font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor.withMultipliedAlpha(0.7)))
if range.upperBound != rawString.endIndex {
string.append(NSAttributedString(string: String(rawString[range.upperBound...]), font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
}
} else {
string.append(NSAttributedString(string: rawString, font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
}
let textSize = self.text.update(
transition: .immediate,
@ -6338,14 +6334,13 @@ private final class EmptyResultsButtonPaidSearchContent: Component {
self.component = component
self.state = state
let attributedString = NSMutableAttributedString(attributedString: NSAttributedString(string: "Search for * \(component.price)", font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
let attributedString = NSMutableAttributedString(attributedString: NSAttributedString(string: component.strings.ChatList_GlobalSearch_SearchButtonPaidTitle("\(component.price)").string, font: Font.semibold(17.0), textColor: component.theme.list.itemCheckColors.foregroundColor))
if let range = attributedString.string.range(of: "*"), let starImage = self.cachedStarImage {
attributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: attributedString.string))
attributedString.addAttribute(.foregroundColor, value: component.theme.list.itemCheckColors.foregroundColor, range: NSRange(range, in: attributedString.string))
attributedString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: attributedString.string))
}
//TODO:localize
let titleSize = self.title.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
@ -6359,7 +6354,7 @@ private final class EmptyResultsButtonPaidSearchContent: Component {
if let unlockTimestamp = component.unlockTimestamp {
var remainingTime: Int32 = unlockTimestamp - Int32(Date().timeIntervalSince1970)
remainingTime = max(0, remainingTime)
subtitleText = "free search unlocks in \(stringForRemainingTime(remainingTime))"
subtitleText = component.strings.ChatList_GlobalSearch_SearchButtonPaidSubtitle(stringForRemainingTime(remainingTime)).string
if self.timer == nil {
self.timer = Foundation.Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { [weak self] _ in
@ -6484,7 +6479,7 @@ private final class EmptyResultsButton: Component {
isEnabled = false
buttonContent = AnyComponentWithIdentity(id: "empty", component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Search",
string: component.strings.ChatList_GlobalSearch_SearchButton,
font: Font.medium(17.0),
textColor: component.theme.list.itemCheckColors.foregroundColor
))
@ -6492,7 +6487,7 @@ private final class EmptyResultsButton: Component {
case .premiumRequired:
buttonContent = AnyComponentWithIdentity(id: "premium", component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Subscribe to Premium",
string: component.strings.ChatList_GlobalSearch_SearchButtonPremium,
font: Font.medium(17.0),
textColor: component.theme.list.itemCheckColors.foregroundColor
))

View File

@ -837,7 +837,6 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
)
}
//TODO:localize
if arguments.areStarReactionsEnabled && !hadStars && !mappedReactions.isEmpty {
var centerAnimation: TelegramMediaFile?
let animationFileId: Int64? = nil

View File

@ -477,8 +477,9 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
case "telegram_call":
actionTitle = item.presentationData.strings.Chat_ViewGroupCall
case "telegram_collection":
//TODO:localize
actionTitle = "VIEW COLLECTION"
actionTitle = item.presentationData.strings.Chat_ViewCollection
case "telegram_story_album":
actionTitle = item.presentationData.strings.Chat_ViewAlbum
default:
break
}

View File

@ -107,7 +107,6 @@ public final class PeerInfoRatingComponent: Component {
let iconSize = CGSize(width: 26.0, height: 26.0)
//TODO:localize
if previousComponent?.level != level || previousComponent?.borderColor != component.borderColor || previousComponent?.foregroundColor != component.foregroundColor || previousComponent?.backgroundColor != component.backgroundColor || "".isEmpty {
let attributedText = NSAttributedString(string: "\(level)", attributes: [
NSAttributedString.Key.font: Font.semibold(10.0),

View File

@ -1978,7 +1978,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.subtitleRating = subtitleRating
}
//TODO:localize
subtitleRatingSize = subtitleRating.update(
transition: subtitleRatingTransition,
component: AnyComponent(PeerInfoRatingComponent(

View File

@ -11701,12 +11701,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
var items: [ContextMenuItem] = []
let strings = self.presentationData.strings
let _ = strings
var ignoreNextActions = false
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Add Stories", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_MenuAddStories, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
if ignoreNextActions {
@ -11721,7 +11719,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
})))
if let _ = pane.currentStoryFolder {
items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuShare, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
}, action: { [weak pane] _, a in
if ignoreNextActions {
@ -11755,7 +11753,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
if let folder = pane.currentStoryFolder {
let _ = folder
items.append(.action(ContextMenuActionItem(text: "Delete Album", textColor: .destructive, icon: { theme in
items.append(.action(ContextMenuActionItem(text: strings.Stories_MenuDeleteAlbum, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
}, action: { [weak pane] _, a in
if ignoreNextActions {

View File

@ -353,14 +353,11 @@ final class PeerInfoStoryGridScreenComponent: Component {
let buttonText: String
var buttonIsEnabled = true
if component.selectionModeCompletion != nil {
//TODO:localize
if self.selectedCount == 0 {
buttonText = "Add Stories"
buttonText = environment.strings.Stories_AddStoriesEmpty
buttonIsEnabled = false
} else if self.selectedCount == 1 {
buttonText = "Add 1 Story"
} else {
buttonText = "Add \(self.selectedCount) Stories"
buttonText = environment.strings.Stories_AddStories(Int32(self.selectedCount))
}
} else {
switch component.scope {
@ -679,8 +676,7 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
if self.selectionModeCompletion != nil {
//TODO:localize
self.titleView?.titleContent = .custom("Add Stories", nil, false)
self.titleView?.titleContent = .custom(presentationData.strings.Stories_AddStoriesTitle, nil, false)
} else {
switch self.scope {
case .saved:

View File

@ -2507,8 +2507,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
if canManage, case let .peer(peerId, _, isArchived) = self.scope {
if !isArchived && self.canManageStories && self.isProfileEmbedded {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Add to Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddToFolder"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuAddToAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddToFolder"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
guard let self, let c else {
f(.default)
return
@ -2529,7 +2528,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
})))
items.append(.separator)
items.append(.action(ContextMenuActionItem(text: "New Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddFolder"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuNewAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddFolder"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in
guard let self else {
f(.default)
return
@ -2786,8 +2785,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
if canManage {
if let folder = self.currentStoryFolder {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Remove from Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/RemoveFromFolderUp"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuRemoveFromAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/RemoveFromFolderUp"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
guard let self else {
f(.default)
return
@ -2924,8 +2922,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
if state.isLoading {
title = self.presentationData.strings.BotPreviews_SubtitleLoading
} else {
//TODO:localize
title = "no stories"
title = self.presentationData.strings.Stories_StatusEmpty
}
}
} else if case let .peer(_, isSaved, isArchived) = self.scope {
@ -3849,10 +3846,9 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
mainTitle = self.presentationData.strings.BotPreviews_LanguageTab_Main
addTitle = self.presentationData.strings.BotPreviews_LanguageTab_Add
} else {
//TODO:localize
mainTitle = "All Stories"
mainTitle = self.presentationData.strings.Stories_AlbumAll
if self.currentStoryFolders.count < self.maxStoryFolders {
addTitle = "+ Add Album"
addTitle = self.presentationData.strings.Stories_AlbumAdd
} else {
addTitle = nil
}
@ -3899,8 +3895,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
canAddStories = await self.canAddStoriesToFolder(folder: folder)
}
if canAddStories {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Add Stories", icon: { theme in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_MenuAddStories, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
guard let self else {
@ -3915,8 +3910,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
}
if self.canManageStories {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Rename Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuRenameAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
guard let self else {
c?.dismiss(completion: nil)
return
@ -3930,8 +3924,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
})
})))
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuShare, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
guard let self else {
c?.dismiss(completion: nil)
return
@ -3947,8 +3940,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
}
if self.canManageStories {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Reorder", icon: { theme in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.BotPreviews_MenuReorder, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
guard let self else {
@ -3961,8 +3953,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
self.beginReordering()
})))
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Delete Album", textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, _ in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Stories_MenuDeleteAlbum, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, _ in
guard let self else {
c?.dismiss(completion: nil)
return
@ -4477,12 +4468,11 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
self.actionPanel = actionPanel
}
//TODO:localize
let actionPanelSize = actionPanel.update(
transition: actionPanelTransition,
component: AnyComponent(BottomButtonPanelComponent(
theme: presentationData.theme,
title: "Add Stories",
title: presentationData.strings.Stories_AddStoriesEmpty,
label: nil,
icon: AnyComponentWithIdentity(id: 0, component: AnyComponent(BundleIconComponent(
name: "Item List/AddItemIcon",
@ -4534,7 +4524,6 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
self.emptyStateView = emptyStateView
}
//TODO:localize
let emptyStateSize = emptyStateView.update(
transition: emptyStateTransition,
component: AnyComponent(EmptyStateIndicatorComponent(
@ -4542,9 +4531,9 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
theme: presentationData.theme,
fitToHeight: self.isProfileEmbedded,
animationName: nil,
title: "Organize Your Stories",
text: "Add some stories to this album.",
actionTitle: "Add to Album",
title: presentationData.strings.Stories_AlbumEmptyTitle,
text: presentationData.strings.Stories_AlbumEmptyText,
actionTitle: presentationData.strings.Stories_AlbumEmptyButton,
action: { [weak self] in
guard let self, let currentStoryFolder = self.currentStoryFolder else {
return
@ -5007,15 +4996,14 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
}
private func presentAddStoryFolder(addItems: [EngineStoryItem] = []) {
//TODO:localize
let promptController = promptController(
sharedContext: self.context.sharedContext,
updatedPresentationData: nil,
text: "Create a New Album",
text: self.presentationData.strings.Stories_CreateAlbum_Title,
titleFont: .bold,
subtitle: "Choose a name for your album and start adding your stories there.",
subtitle: self.presentationData.strings.Stories_CreateAlbum_Text,
value: "",
placeholder: "Title",
placeholder: self.presentationData.strings.Stories_CreateAlbum_Placeholder,
characterLimit: 20,
displayCharacterLimit: true,
apply: { [weak self] value in
@ -5041,15 +5029,14 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
}
private func presentRenameStoryFolder(id: Int64, title: String) {
//TODO:localize
let promptController = promptController(
sharedContext: self.context.sharedContext,
updatedPresentationData: nil,
text: "Edit Album Name",
text: self.presentationData.strings.Stories_EditAlbum_Title,
titleFont: .bold,
subtitle: "Choose a new name for your album.",
subtitle: self.presentationData.strings.Stories_EditAlbum_Text,
value: title,
placeholder: "Title",
placeholder: self.presentationData.strings.Stories_CreateAlbum_Placeholder,
characterLimit: 20,
displayCharacterLimit: true,
apply: { [weak self] value in
@ -5133,13 +5120,12 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
controller?.dismissAnimated()
}
//TODO:localize
let title: String = "Delete \(folder.title)?"
let title: String = presentationData.strings.Stories_DeleteAlbum_Confirmation(folder.title).string
controller.setItemGroups([
ActionSheetItemGroup(items: [
ActionSheetTextItem(title: title),
ActionSheetButtonItem(title: "Delete", color: .destructive, action: { [weak self] in
ActionSheetButtonItem(title: presentationData.strings.Common_Delete, color: .destructive, action: { [weak self] in
dismissAction()
guard let self else {

View File

@ -342,12 +342,11 @@ private final class ProfileLevelInfoScreenComponent: Component {
let clippingY: CGFloat
//TODO:localize
let titleString: String = "Rating"
let titleString: String = environment.strings.ProfileLevelInfo_Title
let descriptionTextString: String
var secondaryDescriptionTextString: String?
if component.peer.id == component.context.account.peerId {
descriptionTextString = "The rating reflects your activity on Telegram. What affects it:"
descriptionTextString = environment.strings.ProfileLevelInfo_MyText
let timestamp = Int32(Date().timeIntervalSince1970)
if let pendingStarRating = component.pendingStarRating, pendingStarRating.timestamp > timestamp {
@ -359,15 +358,15 @@ private final class ProfileLevelInfoScreenComponent: Component {
} else {
let dayCount = (pendingStarRating.timestamp - timestamp) / (24 * 60 * 60)
if dayCount == 0 {
secondaryDescriptionTextString = "The rating updates today.\n\(pendingPoints) points are pending."
secondaryDescriptionTextString = environment.strings.ProfileLevelInfo_MyDescriptionToday(Int32(pendingPoints))
} else {
secondaryDescriptionTextString = "The rating updates in \(dayCount) days after purchases.\n\(pendingPoints) points are pending."
secondaryDescriptionTextString = environment.strings.ProfileLevelInfo_MyDescription(environment.strings.ProfileLevelInfo_MyDescriptionDays(Int32(dayCount)), environment.strings.ProfileLevelInfo_MyDescriptionPoints(Int32(pendingPoints))).string
}
}
}
}
} else {
descriptionTextString = "The rating reflects **\(component.peer.compactDisplayTitle)'s** activity on Telegram. What affects it:"
descriptionTextString = environment.strings.ProfileLevelInfo_OtherDescription(component.peer.compactDisplayTitle).string
}
let titleSize = self.title.update(
@ -438,11 +437,11 @@ private final class ProfileLevelInfoScreenComponent: Component {
component: AnyComponent(PremiumLimitDisplayComponent(
inactiveColor: environment.theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5),
activeColors: gradientColors,
inactiveTitle: "Level \(component.starRating.level)",
inactiveTitle: environment.strings.ProfileLevelInfo_LevelIndex(Int32(currentLevel)),
inactiveValue: "",
inactiveTitleColor: environment.theme.list.itemPrimaryTextColor,
activeTitle: "",
activeValue: nextLevel.flatMap { "Level \($0)" } ?? "",
activeValue: nextLevel.flatMap { environment.strings.ProfileLevelInfo_LevelIndex(Int32($0)) } ?? "",
activeTitleColor: .white,
badgeIconName: "Peer Info/ProfileLevelProgressIcon",
badgeText: badgeText,
@ -659,8 +658,7 @@ private final class ProfileLevelInfoScreenComponent: Component {
contentHeight += 31.0
//TODO:localize
let actionButtonTitle: String = "Understood"
let actionButtonTitle: String = environment.strings.ProfileLevelInfo_CloseButton
var buttonTitle: [AnyComponentWithIdentity<Empty>] = []
let playButtonAnimation = ActionSlot<Void>()

View File

@ -991,15 +991,14 @@ final class ShareWithPeersScreenComponent: Component {
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
//TODO:localize
let promptController = promptController(
sharedContext: component.context.sharedContext,
updatedPresentationData: (initial: presentationData, signal: .single(presentationData)),
text: "Create a New Album",
text: presentationData.strings.Stories_CreateAlbum_Title,
titleFont: .bold,
subtitle: "Choose a name for your album and start adding your stories there.",
subtitle: presentationData.strings.Stories_CreateAlbum_Text,
value: "",
placeholder: "Title",
placeholder: presentationData.strings.Stories_CreateAlbum_Placeholder,
characterLimit: 20,
apply: { [weak self] value in
guard let self, let component = self.component else {
@ -1855,17 +1854,15 @@ final class ShareWithPeersScreenComponent: Component {
self.visibleItems[itemId] = visibleItem
}
//TODO:localize
var foldersText = "All Stories"
var foldersText = environment.strings.Stories_Post_AlbumAll
if !self.shareToFolders.isEmpty {
if self.shareToFolders.count == 1 {
foldersText = self.shareToFolders[0].title
} else {
foldersText = "\(self.shareToFolders.count) Albums"
foldersText = environment.strings.Stories_Post_AlbumCount(Int32(self.shareToFolders.count))
}
}
//TODO:localize
let _ = visibleItem.update(
transition: itemTransition,
component: AnyComponent(ListActionItemComponent(
@ -1874,7 +1871,7 @@ final class ShareWithPeersScreenComponent: Component {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Album",
string: environment.strings.Stories_Post_Album,
font: Font.regular(17.0),
textColor: environment.theme.list.itemPrimaryTextColor
)),
@ -1977,7 +1974,7 @@ final class ShareWithPeersScreenComponent: Component {
footerText = isSendAsGroup ? environment.strings.Story_Privacy_ChooseCoverGroupInfo : environment.strings.Story_Privacy_ChooseCoverChannelInfo
}
if component.coverItem == nil {
footerText = "Choose the albums where you want to share your story."
footerText = environment.strings.Stories_Post_AlbumFooter
}
let footerSize = sectionFooter.update(

View File

@ -6109,8 +6109,7 @@ public final class StoryItemSetContainerComponent: Component {
var items: [ContextMenuItem] = []
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Add to Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddToFolder"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
items.append(.action(ContextMenuActionItem(text: component.strings.Stories_MenuAddToAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddToFolder"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
guard let self, let c else {
f(.default)
return
@ -6131,7 +6130,7 @@ public final class StoryItemSetContainerComponent: Component {
})))
items.append(.separator)
items.append(.action(ContextMenuActionItem(text: "New Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddFolder"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in
items.append(.action(ContextMenuActionItem(text: component.strings.Stories_MenuNewAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddFolder"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in
guard let self else {
f(.default)
return
@ -7142,11 +7141,11 @@ public final class StoryItemSetContainerComponent: Component {
let promptController = promptController(
sharedContext: component.context.sharedContext,
updatedPresentationData: (initial: presentationData, signal: .single(presentationData)),
text: "Create a New Album",
text: presentationData.strings.Stories_CreateAlbum_Title,
titleFont: .bold,
subtitle: "Choose a name for your album and start adding your stories there.",
subtitle: presentationData.strings.Stories_CreateAlbum_Text,
value: "",
placeholder: "Title",
placeholder: presentationData.strings.Stories_CreateAlbum_Placeholder,
characterLimit: 20,
apply: { [weak self] value in
guard let self, let component = self.component else {

View File

@ -787,8 +787,7 @@ public final class AccountContextImpl: AccountContext {
}
} else if case .peer = currentCallType {
let text: String
//TODO:localize
text = "End current call and start a conference?";
text = presentationData.strings.Call_AlertMoveToConference
strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_CallInProgressTitle, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
guard let self else {
return