Update localization

This commit is contained in:
Ilya Laktyushin 2025-12-03 22:25:26 +04:00
parent 52e7a175c4
commit 4660f67271
8 changed files with 92 additions and 129 deletions

View file

@ -15539,12 +15539,56 @@ Error: %8$@";
"Passkeys.AddPasskey" = "Create Passkey";
"Passkeys.ListFooter" = "Your passkeys are stored securely in your password manager.";
"Gifts.Demo.Title" = "Unique Collectibles";
"Gifts.Demo.Description" = "Telegram Gifts are collectible items you can trade or showcase on your profile.";
"Gifts.Demo.Unique.Title" = "Unique";
"Gifts.Demo.Unique.Text" = "Upgrade your gifts to get a unique number, model, backdrop and symbol.";
"Gifts.Demo.Tradable.Title" = "Tradable";
"Gifts.Demo.Tradable.Text" = "Sell your gift on Telegram or on third-party NFT marketplaces.";
"Gifts.Demo.Wearable.Title" = "Wearable";
"Gifts.Demo.Wearable.Text" = "Display gifts on your page and set them as profile covers or statuses.";
"Gifts.Demo.Understood" = "Understood";
"Gift.Demo.Title" = "Unique Collectibles";
"Gift.Demo.Description" = "Telegram Gifts are collectible items you can trade or showcase on your profile.";
"Gift.Demo.Unique.Title" = "Unique";
"Gift.Demo.Unique.Text" = "Upgrade your gifts to get a unique number, model, backdrop and symbol.";
"Gift.Demo.Tradable.Title" = "Tradable";
"Gift.Demo.Tradable.Text" = "Sell your gift on Telegram or on third-party NFT marketplaces.";
"Gift.Demo.Wearable.Title" = "Wearable";
"Gift.Demo.Wearable.Text" = "Display gifts on your page and set them as profile covers or statuses.";
"Gift.Demo.Understood" = "Understood";
"Gift.Variants.RandomTraits" = "Random Traits";
"Gift.Variants.SelectedTraits" = "Selected Traits";
"Gift.Variants.Randomize" = "Randomize Traits";
"Gift.Variants.Model" = "model";
"Gift.Variants.Backdrop" = "backdrop";
"Gift.Variants.Symbol" = "symbol";
"Gift.Variants.Models" = "Models";
"Gift.Variants.Backdrops" = "Backdrops";
"Gift.Variants.Symbols" = "Symbols";
"Gift.Variants.CollectionInfo" = "This collection features";
"Gift.Variants.CollectionInfo.Model_1" = "%@ unique model";
"Gift.Variants.CollectionInfo.Model_any" = "%@ unique models";
"Gift.Variants.CollectionInfo.Backdrop_1" = "%@ unique backdrop";
"Gift.Variants.CollectionInfo.Backdrop_any" = "%@ unique backdrops";
"Gift.Variants.CollectionInfo.Symbol_1" = "%@ unique symbol";
"Gift.Variants.CollectionInfo.Symbol_any" = "%@ unique symbols";
"Gift.Auction.GiftAuction" = "Upcoming Auction";
"Gift.Auction.UpcomingAuction" = "Upcoming Auction";
"Gift.Auction.LearnMore" = "Learn more about Telegram Gifts >";
"Gift.AuctionBid.UpcomingTitle" = "Place an Early Bid";
"Gift.View.Context.BuyOffer" = "Offer to Buy";
"Gift.Offer.Title" = "Offer to Buy";
"Gift.Offer.OfferStars" = "Offer Stars";
"Gift.Offer.OfferTon" = "Offer TON";
"Gift.Offer.PriceSectionStars" = "STARS TO OFFER";
"Gift.Offer.PriceSectionTon" = "TON TO OFFER";
"Gift.Offer.PricePlaceholder" = "Price";
"Gift.Offer.PriceDescriptionStars" = "Enter the number of Stars you'd like to offer for **%@**.";
"Gift.Offer.PriceDescriptionTon" = "Enter the number of TON you'd like to offer for **%@**.";
"Gift.Offer.Duration" = "Offer Duration";
"Gift.Offer.DurationDescriptionStars" = "Choose how long **%@** can accept your offer. When the time expires, your Stars will be automatically refunded.";
"Gift.Offer.DurationDescriptionTon" = "Choose how long **%@** can accept your offer. When the time expires, your TON will be automatically refunded.";
"Gift.Offer.Duration.Hours_1" = "%@ Hour";
"Gift.Offer.Duration.Hours_any" = "%@ Hours";
"Gift.Offer.Offer" = "Offer";
"Notification.StarGift.Sold" = "sold";

View file

@ -717,8 +717,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
}
text = isStoryEntity ? "**\(item.presentationData.strings.Notification_StarGift_Collectible) #\(formatCollectibleNumber(uniqueGift.number, dateTimeFormat: item.presentationData.dateTimeFormat))**" : "**\(uniqueGift.title) #\(formatCollectibleNumber(uniqueGift.number, dateTimeFormat: item.presentationData.dateTimeFormat))**"
if fromOffer {
//TODO:localize
ribbonTitle = incoming ? "" : "sold"
ribbonTitle = incoming ? "" : item.presentationData.strings.Notification_StarGift_Sold
customRibbonColors = [UIColor(rgb: 0xd9433a), UIColor(rgb: 0xff645b)]
} else {
ribbonTitle = isStoryEntity ? "" : item.presentationData.strings.Notification_StarGift_Gift

View file

@ -316,7 +316,7 @@ private final class DemoSheetContent: CombinedComponent {
playOnce: state.playButtonAnimation
))))
buttonTitle.append(AnyComponentWithIdentity(id: 1, component: AnyComponent(ButtonTextContentComponent(
text: strings.Gifts_Demo_Understood,
text: strings.Gift_Demo_Understood,
badge: 0,
textColor: theme.list.itemCheckColors.foregroundColor,
badgeBackground: theme.list.itemCheckColors.foregroundColor,
@ -497,7 +497,7 @@ private final class GiftDemoListComponent: CombinedComponent {
var contentSize = CGSize(width: context.availableSize.width, height: 32.0)
let title = title.update(
component: MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Gifts_Demo_Title, font: Font.bold(25.0), textColor: titleColor))),
component: MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Gift_Demo_Title, font: Font.bold(25.0), textColor: titleColor))),
availableSize: context.availableSize,
transition: context.transition
)
@ -509,7 +509,7 @@ private final class GiftDemoListComponent: CombinedComponent {
let description = description.update(
component: BalancedTextComponent(
text: .plain(NSAttributedString(string: strings.Gifts_Demo_Description, font: Font.regular(15.0), textColor: textColor)),
text: .plain(NSAttributedString(string: strings.Gift_Demo_Description, font: Font.regular(15.0), textColor: textColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.2
@ -528,9 +528,9 @@ private final class GiftDemoListComponent: CombinedComponent {
AnyComponentWithIdentity(
id: "unique",
component: AnyComponent(InfoParagraphComponent(
title: strings.Gifts_Demo_Unique_Title,
title: strings.Gift_Demo_Unique_Title,
titleColor: titleColor,
text: strings.Gifts_Demo_Unique_Text,
text: strings.Gift_Demo_Unique_Text,
textColor: textColor,
accentColor: iconColor,
iconName: "Premium/Collectible/Unique",
@ -542,9 +542,9 @@ private final class GiftDemoListComponent: CombinedComponent {
AnyComponentWithIdentity(
id: "tradable",
component: AnyComponent(InfoParagraphComponent(
title: strings.Gifts_Demo_Tradable_Title,
title: strings.Gift_Demo_Tradable_Title,
titleColor: titleColor,
text: strings.Gifts_Demo_Tradable_Text,
text: strings.Gift_Demo_Tradable_Text,
textColor: textColor,
accentColor: iconColor,
iconName: "Premium/Collectible/Transferable",
@ -556,9 +556,9 @@ private final class GiftDemoListComponent: CombinedComponent {
AnyComponentWithIdentity(
id: "wearable",
component: AnyComponent(InfoParagraphComponent(
title: strings.Gifts_Demo_Wearable_Title,
title: strings.Gift_Demo_Wearable_Title,
titleColor: titleColor,
text: strings.Gifts_Demo_Wearable_Text,
text: strings.Gift_Demo_Wearable_Text,
textColor: textColor,
accentColor: iconColor,
iconName: "Premium/Collectible/Tradable",

View file

@ -2697,8 +2697,7 @@ private final class GiftAuctionBidScreenComponent: Component {
let titleString: String
if isUpcoming {
//TODO:localize
titleString = "Place an Early Bid"
titleString = environment.strings.Gift_AuctionBid_UpcomingTitle
} else {
titleString = environment.strings.Gift_AuctionBid_Title
}

View file

@ -677,8 +677,7 @@ private final class GiftAuctionViewSheetContent: CombinedComponent {
)
))
} else {
//TODO:localize
descriptionText = isUpcoming ? "Upcoming Auction" : "Gift Auction"
descriptionText = isUpcoming ? strings.Gift_Auction_UpcomingAuction : strings.Gift_Auction_GiftAuction
tableItems.append(.init(
id: "start",
@ -805,8 +804,7 @@ private final class GiftAuctionViewSheetContent: CombinedComponent {
state.cachedSmallChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: linkColor)!, theme)
}
//TODO:localize
let learnMoreAttributedString = parseMarkdownIntoAttributedString("Learn more about Telegram Gifts >", attributes: markdownAttributes, textAlignment: .center).mutableCopy() as! NSMutableAttributedString
let learnMoreAttributedString = parseMarkdownIntoAttributedString(strings.Gift_Auction_LearnMore, attributes: markdownAttributes, textAlignment: .center).mutableCopy() as! NSMutableAttributedString
if let range = learnMoreAttributedString.string.range(of: ">"), let chevronImage = state.cachedSmallChevronImage?.0 {
learnMoreAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: learnMoreAttributedString.string))
}

View file

@ -856,81 +856,6 @@ private final class GiftUpgradePreviewScreenComponent: Component {
contentHeight += descriptionSize.height
contentHeight += 26.0
////
//// var validKeys: Set<Int64> = Set()
//// for auctionState in self.auctionStates {
//// let id = auctionState.gift.giftId
//// validKeys.insert(id)
////
//// let itemView: ComponentView<Empty>
//// if let current = self.itemsViews[id] {
//// itemView = current
//// } else {
//// itemView = ComponentView()
//// self.itemsViews[id] = itemView
//// }
////
//// let itemSize = itemView.update(
//// transition: transition,
//// component: AnyComponent(
//// ActiveAuctionComponent(
//// context: component.context,
//// theme: theme,
//// strings: environment.strings,
//// dateTimeFormat: environment.dateTimeFormat,
//// state: auctionState,
//// currentTime: currentTime,
//// action: { [weak self] in
//// guard let self, let component = self.component else {
//// return
//// }
//// if let giftAuctionsManager = component.context.giftAuctionsManager {
//// let _ = (giftAuctionsManager.auctionContext(for: .giftId(id))
//// |> deliverOnMainQueue).start(next: { [weak self] auction in
//// guard let self, let component = self.component, let auction, let controller = environment.controller(), let navigationController = controller.navigationController as? NavigationController else {
//// return
//// }
//// let bidController = component.context.sharedContext.makeGiftAuctionBidScreen(context: component.context, toPeerId: auction.currentBidPeerId ?? component.context.account.peerId, text: nil, entities: nil, hideName: false, auctionContext: auction, acquiredGifts: nil)
//// navigationController.pushViewController(bidController)
//// })
//// }
//// }
//// )
//// ),
//// environment: {},
//// containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0)
//// )
//// let itemFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: itemSize)
//// if let view = itemView.view {
//// if view.superview == nil {
//// self.scrollContentView.addSubview(view)
//// }
//// view.frame = itemFrame
//// }
//// contentHeight += itemSize.height
//// contentHeight += 20.0
//// }
//// contentHeight -= 10.0
//
// var removeKeys: [Int64] = []
// for (id, item) in self.itemsViews {
// if !validKeys.contains(id) {
// removeKeys.append(id)
//
// if let itemView = item.view {
// transition.setAlpha(view: itemView, alpha: 0.0, completion: { _ in
// itemView.removeFromSuperview()
// })
// }
// }
// }
// for id in removeKeys {
// self.itemsViews.removeValue(forKey: id)
// }
if self.backgroundHandleView.image == nil {
self.backgroundHandleView.image = generateStretchableFilledCircleImage(diameter: 5.0, color: .white)?.withRenderingMode(.alwaysTemplate)
}

View file

@ -1438,9 +1438,8 @@ private final class GiftViewSheetContent: CombinedComponent {
self?.shareGift()
})))
//TODO:localize
if case let .unique(uniqueGift) = arguments.gift, case let .peerId(ownerPeerId) = uniqueGift.owner, ownerPeerId != self.context.account.peerId, uniqueGift.minOfferStars != nil {
items.append(.action(ContextMenuActionItem(text: "Offer to Buy", icon: { theme in
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_BuyOffer, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Paid"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] c, _ in
c?.dismiss(completion: nil)

View file

@ -240,18 +240,18 @@ private final class SheetContent: CombinedComponent {
amountLabel = "~\(formatTonUsdValue(amount.value, divide: false, rate: usdRate, dateTimeFormat: environment.dateTimeFormat))"
}
}
case .starGiftOffer:
titleString = "Offer to Buy"
case let .starGiftOffer(_, gift, _):
titleString = environment.strings.Gift_Offer_Title
switch state.currency {
case .stars:
amountTitle = "STARS TO OFFER"
minAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMinStarsAmount, nanos: 0)
amountTitle = environment.strings.Gift_Offer_PriceSectionStars
minAmount = StarsAmount(value: gift.minOfferStars ?? resaleConfiguration.starGiftResaleMinStarsAmount, nanos: 0)
case .ton:
amountTitle = "TON TO OFFER"
minAmount = StarsAmount(value: 0, nanos: 0)
amountTitle = environment.strings.Gift_Offer_PriceSectionTon
minAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMinTonAmount, nanos: 0)
}
maxAmount = nil
amountPlaceholder = "Price"
amountPlaceholder = environment.strings.Gift_Offer_PricePlaceholder
if let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate, let tonUsdRate = withdrawConfiguration.tonUsdRate, let amount = state.amount, amount > StarsAmount.zero {
switch state.currency {
@ -358,10 +358,9 @@ private final class SheetContent: CombinedComponent {
tonTitle = environment.strings.Chat_PostSuggestion_Suggest_RequestTon
}
case .starGiftOffer:
//TODO:localize
displayCurrencySelector = true
starsTitle = "Offer Stars"
tonTitle = "Offer TON"
starsTitle = environment.strings.Gift_Offer_OfferStars
tonTitle = environment.strings.Gift_Offer_OfferTon
default:
starsTitle = ""
tonTitle = ""
@ -555,9 +554,9 @@ private final class SheetContent: CombinedComponent {
let string: String
switch state.currency {
case .stars:
string = "Enter the number of Stars you'd like to offer for **\(giftTitle)**."
string = environment.strings.Gift_Offer_PriceDescriptionStars(giftTitle).string
case .ton:
string = "Enter the number of TON you'd like to offer for **\(giftTitle)**."
string = environment.strings.Gift_Offer_PriceDescriptionTon(giftTitle).string
}
let amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(string, attributes: amountMarkdownAttributes, textAlignment: .natural))
amountFooter = AnyComponent(MultilineTextComponent(
@ -801,9 +800,9 @@ private final class SheetContent: CombinedComponent {
let footerString: String
switch state.currency {
case .stars:
footerString = "Choose how long **\(peerName)** can accept your offer. When the time expires, your Stars will be automatically refunded."
footerString = environment.strings.Gift_Offer_DurationDescriptionStars(peerName).string
case .ton:
footerString = "Choose how long **\(peerName)** can accept your offer. When the time expires, your TON will be automatically refunded."
footerString = environment.strings.Gift_Offer_DurationDescriptionTon(peerName).string
}
let periodFooterString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(footerString, attributes: amountMarkdownAttributes, textAlignment: .natural))
@ -813,12 +812,7 @@ private final class SheetContent: CombinedComponent {
))
let hours = state.duration / 3600
let durationString: String
if hours == 1 {
durationString = "1 Hour"
} else {
durationString = "\(hours) Hours"
}
let durationString = environment.strings.Gift_Offer_Duration_Hours(hours)
let periodSection = periodSection.update(
component: ListSectionComponent(
@ -834,7 +828,7 @@ private final class SheetContent: CombinedComponent {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "Offer Duration",
string: environment.strings.Gift_Offer_Duration,
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemPrimaryTextColor
)),
@ -930,9 +924,9 @@ private final class SheetContent: CombinedComponent {
currencySymbol = "$"
currencyAmount = formatTonAmountText(amount.value, dateTimeFormat: environment.dateTimeFormat, maxDecimalPositions: nil)
}
buttonString = "Offer \(currencySymbol) \(currencyAmount)"
buttonString = "\(environment.strings.Gift_Offer_Offer) \(currencySymbol) \(currencyAmount)"
} else {
buttonString = "Offer"
buttonString = environment.strings.Gift_Offer_Offer
}
} else if let amount = state.amount {
buttonString = "\(environment.strings.Stars_Withdraw_Withdraw) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"
@ -1085,10 +1079,11 @@ private final class SheetContent: CombinedComponent {
if state.isPickingDuration {
let sourceFrame = CGRect(origin: CGPoint(x: durationFrame.maxX - 52.0, y: durationFrame.minY + 120.0), size: CGSize(width: 52.0, height: 52.0))
let durationPicker = durationPicker.update(
component: MenuComponent(
theme: theme,
sourceFrame: durationFrame.offsetBy(dx: 0.0, dy: 120.0),
sourceFrame: sourceFrame,
component: AnyComponent(DurationMenuComponent(
theme: theme,
strings: environment.strings,
@ -1147,6 +1142,7 @@ private final class SheetContent: CombinedComponent {
fileprivate var component: SheetContent
fileprivate var forceUpdateAmount = false
fileprivate var amount: StarsAmount?
fileprivate var currency: CurrencyAmount.Currency = .stars
fileprivate var timestamp: Int32?
@ -1246,7 +1242,7 @@ private final class SheetContent: CombinedComponent {
self.currency = .stars
}
} else {
let _ = (context.engine.payments.cachedStarGifts()
let _ = (self.context.engine.payments.cachedStarGifts()
|> filter { $0 != nil }
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] gifts in
@ -1264,6 +1260,7 @@ private final class SheetContent: CombinedComponent {
}
if case let .generic(genericGift) = matchingGift, let minResaleStars = genericGift.availability?.minResaleStars {
self.amount = StarsAmount(value: max(minResaleStars, resaleConfiguration.starGiftResaleMinStarsAmount), nanos: 0)
self.forceUpdateAmount = true
self.updated()
}
})
@ -1417,6 +1414,7 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
if let view = self.node.hostView.findTaggedView(tag: amountTag) as? AmountFieldComponent.View {
Queue.mainQueue().after(0.01) {
view.resetValue()
view.activateInput()
view.selectAll()
}
@ -1810,6 +1808,7 @@ public final class AmountFieldComponent: Component {
return
}
self.textField.text = "\(value)"
self.placeholderView.view?.isHidden = self.textField.text?.isEmpty ?? false
}
func update(component: AmountFieldComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
@ -1829,10 +1828,10 @@ public final class AmountFieldComponent: Component {
text = "\(formatTonAmountText(value, dateTimeFormat: PresentationDateTimeFormat(timeFormat: component.dateTimeFormat.timeFormat, dateFormat: component.dateTimeFormat.dateFormat, dateSeparator: "", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: ""), maxDecimalPositions: nil))"
}
self.textField.text = text
self.didSetValueOnce = true
} else {
self.textField.text = ""
}
self.didSetValueOnce = true
}
self.textField.font = Font.regular(17.0)