diff --git a/src/components/sidebarLeft/tabs/language.ts b/src/components/sidebarLeft/tabs/language.ts index 25763ad3..15980655 100644 --- a/src/components/sidebarLeft/tabs/language.ts +++ b/src/components/sidebarLeft/tabs/language.ts @@ -21,11 +21,22 @@ export default class AppLanguageTab extends SliderSuperTab { const radioRows: Map = new Map(); - const promise = this.managers.apiManager.invokeApiCacheable('langpack.getLanguages', { - lang_pack: 'macos' - }).then((languages) => { + const promise = Promise.all([ + this.managers.apiManager.invokeApiCacheable('langpack.getLanguages', { + lang_pack: 'web' + }), + this.managers.apiManager.invokeApiCacheable('langpack.getLanguages', { + lang_pack: 'macos' + }), + ]).then(([languages1, languages2]) => { + const rendered: Set = new Set(); + const webLangCodes = languages1.map((language) => language.lang_code); + const random = randomLong(); - languages.forEach((language) => { + languages1.concat(languages2).forEach((language) => { + if(rendered.has(language.lang_code)) return; + rendered.add(language.lang_code); + const row = new Row({ radioField: new RadioField({ text: language.name, @@ -39,7 +50,7 @@ export default class AppLanguageTab extends SliderSuperTab { }); const form = RadioFormFromRows([...radioRows.values()], (value) => { - I18n.getLangPack(value); + I18n.getLangPack(value, webLangCodes.includes(value)); }); I18n.getCacheLangPack().then((langPack) => { diff --git a/src/lang.ts b/src/lang.ts index 3aeacdfb..dc4684fd 100644 --- a/src/lang.ts +++ b/src/lang.ts @@ -690,8 +690,8 @@ const lang = { "Devices": "Devices", "LanguageName": "English", "EditCantEditPermissionsPublic": "This permission is not available in public groups.", - "VoipUserMicrophoneIsOff": "%s\'s microphone is off", - "VoipUserCameraIsOff": "%s\'s camera is off", + "VoipUserMicrophoneIsOff": "%s's microphone is off", + "VoipUserCameraIsOff": "%s's camera is off", "PrivacyPhoneInfo4": "This public link opens a chat with you:", "ReportChatIllegalDrugs": "Illegal Drugs", "ReportChatPersonalDetails": "Personal Details", diff --git a/src/lib/langPack.ts b/src/lib/langPack.ts index 549789d1..3acc697f 100644 --- a/src/lib/langPack.ts +++ b/src/lib/langPack.ts @@ -81,9 +81,16 @@ namespace I18n { let cacheLangPackPromise: Promise; export let lastRequestedLangCode: string; + export let lastRequestedNormalizedLangCode: string; export let lastAppliedLangCode: string; export let requestedServerLanguage = false; export let timeFormat: State['settings']['timeFormat']; + + function setLangCode(langCode: string) { + lastRequestedLangCode = langCode; + lastRequestedNormalizedLangCode = langCode.split('-')[0]; + } + export function getCacheLangPack(): Promise { if(cacheLangPackPromise) return cacheLangPackPromise; return cacheLangPackPromise = Promise.all([ @@ -99,7 +106,7 @@ namespace I18n { } */ if(!lastRequestedLangCode) { - lastRequestedLangCode = langPack.lang_code; + setLangCode(langPack.lang_code); } applyLangPack(langPack); @@ -150,7 +157,7 @@ namespace I18n { export function loadLocalLangPack() { const defaultCode = App.langPackCode; - lastRequestedLangCode = defaultCode; + setLangCode(defaultCode); return Promise.all([ import('../lang'), import('../langSign'), @@ -173,15 +180,15 @@ namespace I18n { }); } - export function loadLangPack(langCode: string) { + export function loadLangPack(langCode: string, web?: boolean) { requestedServerLanguage = true; const managers = rootScope.managers; return Promise.all([ managers.apiManager.invokeApiCacheable('langpack.getLangPack', { lang_code: langCode, - lang_pack: App.langPack + lang_pack: web ? 'web' : App.langPack }), - managers.apiManager.invokeApiCacheable('langpack.getLangPack', { + !web && managers.apiManager.invokeApiCacheable('langpack.getLangPack', { lang_code: langCode, lang_pack: 'android' }), @@ -225,20 +232,16 @@ namespace I18n { return pushTo; } - export function getLangPack(langCode: string) { - lastRequestedLangCode = langCode; - return loadLangPack(langCode).then(([langPack1, langPack2, localLangPack1, localLangPack2, countries, _]) => { + export function getLangPack(langCode: string, web?: boolean) { + setLangCode(langCode); + return loadLangPack(langCode, web).then(([langPack1, langPack2, localLangPack1, localLangPack2, countries, _]) => { let strings: LangPackString[] = []; [localLangPack1, localLangPack2].forEach((l) => { formatLocalStrings(l.default as any, strings); }); - strings = strings.concat(langPack1.strings); - - for(const string of langPack2.strings) { - strings.push(string); - } + strings = strings.concat(...[langPack1.strings, langPack2.strings].filter(Boolean)); langPack1.strings = strings; langPack1.countries = countries; @@ -266,15 +269,16 @@ namespace I18n { })(); export function applyLangPack(langPack: LangPackDifference) { - if(langPack.lang_code !== lastRequestedLangCode) { + const currentLangCode = lastRequestedLangCode; + if(langPack.lang_code !== currentLangCode) { return; } try { - pluralRules = new Intl.PluralRules(langPack.lang_code); + pluralRules = new Intl.PluralRules(lastRequestedNormalizedLangCode); } catch(err) { console.error('pluralRules error', err); - pluralRules = new Intl.PluralRules(langPack.lang_code.split('-', 1)[0]); + pluralRules = new Intl.PluralRules(lastRequestedNormalizedLangCode.split('-', 1)[0]); } strings.clear(); @@ -299,9 +303,9 @@ namespace I18n { }); } - if(lastAppliedLangCode !== langPack.lang_code) { - rootScope.dispatchEvent('language_change', langPack.lang_code); - lastAppliedLangCode = langPack.lang_code; + if(lastAppliedLangCode !== currentLangCode) { + rootScope.dispatchEvent('language_change', currentLangCode); + lastAppliedLangCode = currentLangCode; cachedDateTimeFormats.clear(); updateAmPm(); } @@ -500,10 +504,11 @@ namespace I18n { const cachedDateTimeFormats: Map = new Map(); function getDateTimeFormat(options: Intl.DateTimeFormatOptions = {}) { - let json = JSON.stringify(options); + const json = JSON.stringify(options); let dateTimeFormat = cachedDateTimeFormats.get(json); if(!dateTimeFormat) { - cachedDateTimeFormats.set(json, dateTimeFormat = new Intl.DateTimeFormat(lastRequestedLangCode + '-u-hc-' + timeFormat, options)); + dateTimeFormat = new Intl.DateTimeFormat(lastRequestedNormalizedLangCode + '-u-hc-' + timeFormat, options); + cachedDateTimeFormats.set(json, dateTimeFormat); } return dateTimeFormat; diff --git a/src/scripts/out/langPack.strings b/src/scripts/out/langPack.strings index 35bcdfa2..75f3b3ec 100644 --- a/src/scripts/out/langPack.strings +++ b/src/scripts/out/langPack.strings @@ -48,6 +48,8 @@ "Contacts.Count_other" = "%d contacts"; "Deactivated.Title" = "Too many tabs..."; "Deactivated.Subtitle" = "Telegram supports only one active tab with the app.\nClick anywhere to continue using this tab."; +"Deactivated.Version.Title" = "WebK has updated..."; +"Deactivated.Version.Subtitle" = "Another tab is running a newer version of Telegram.\nClick anywhere to reload this tab."; "General.Keyboard" = "Keyboard"; "General.SendShortcut.Enter" = "Send by Enter"; "General.SendShortcut.CtrlEnter" = "Send by %s + Enter"; @@ -90,7 +92,6 @@ "Popup.Unpin.HideTitle" = "Hide pinned messages"; "Popup.Unpin.HideDescription" = "Do you want to hide the pinned message bar? It wil stay hidden until a new message is pinned."; "Popup.Unpin.Hide" = "Hide"; -"TwoStepAuth.InvalidPassword" = "Invalid password"; "TwoStepAuth.EmailCodeChangeEmail" = "Change Email"; "MarkupTooltip.LinkPlaceholder" = "Enter URL..."; "MediaViewer.Context.Download" = "Download"; @@ -109,6 +110,13 @@ "PushNotification.Action.Settings.Mobile" = "Alerts settings"; "PushNotification.Message.NoPreview" = "You have a new message"; "LogOut.Description" = "Are you sure you want to log out?\n\nNote that you can seamlessly use Telegram on all your devices at once."; +"VoiceChat.DiscussionGroup" = "discussion group"; +"PaymentInfo.CVV" = "CVV Code"; +"PaymentInfo.Card.Title" = "Enter your card information"; +"PaymentInfo.Billing.Title" = "Enter your billing address"; +"PaymentInfo.Done" = "PROCEED TO CHECKOUT"; +"PaymentCard.Error.Invalid" = "Invalid card number"; +"PaymentCard.Error.Incomplete" = "Incomplete card number"; "AccDescrEditing" = "Editing"; "ActionCreateChannel" = "Channel created"; "ActionCreateGroup" = "un1 created the group"; @@ -599,6 +607,67 @@ "ResetAutomaticMediaDownloadAlertTitle" = "Reset settings"; "ResetAutomaticMediaDownloadAlert" = "Are you sure you want to reset auto-download settings?"; "Reset" = "Reset"; +"SendMessageAsTitle" = "Send message as..."; +"Devices" = "Devices"; +"LanguageName" = "English"; +"EditCantEditPermissionsPublic" = "This permission is not available in public groups."; +"VoipUserMicrophoneIsOff" = "%s's microphone is off"; +"VoipUserCameraIsOff" = "%s's camera is off"; +"PrivacyPhoneInfo4" = "This public link opens a chat with you:"; +"ReportChatIllegalDrugs" = "Illegal Drugs"; +"ReportChatPersonalDetails" = "Personal Details"; +"VoipPeerIncompatible" = "**%1$s**'s app is using an incompatible protocol. They need to update their app before you can call them."; +"ScamMessage" = "SCAM"; +"FakeMessage" = "FAKE"; +"TextCopied" = "Text copied to clipboard"; +"PaymentInvoice" = "INVOICE"; +"PaymentTestInvoice" = "TEST INVOICE"; +"PaymentReceipt" = "Receipt"; +"PaymentSuccessfullyPaid" = "You successfully transferred %1$s to %2$s for %3$s"; +"PaymentSuccessfullyPaidNoItem" = "You successfully transferred %1$s to %2$s"; +"PaymentCheckout" = "Checkout"; +"PaymentTransactionTotal" = "Total"; +"PaymentTip" = "Tip"; +"PaymentTipOptional" = "Tip (Optional)"; +"PaymentCheckoutPay" = "PAY %1$s"; +"PaymentCheckoutMethod" = "Payment method"; +"PaymentCheckoutProvider" = "Payment provider"; +"PaymentCardNumber" = "Card Number"; +"PaymentCardSavePaymentInformation" = "Save Payment Information"; +"PaymentCardInfo" = "Payment info"; +"PaymentCardSavePaymentInformationInfoLine1" = "You can save your payment info for future use. It will be stored directly with the payment provider. Telegram has no access to your credit card data."; +"Done" = "Done"; +"PaymentShippingMethod" = "Shipping methods"; +"PaymentNoShippingMethod" = "Sorry, it is not possible to deliver to your address."; +"PaymentShippingInfo" = "Shipping Information"; +"PaymentShippingAddress" = "Shipping address"; +"PaymentShippingAddress1Placeholder" = "Address 1 (Street)"; +"PaymentShippingAddress2Placeholder" = "Address 2 (Street)"; +"PaymentShippingCityPlaceholder" = "City"; +"PaymentShippingStatePlaceholder" = "State"; +"PaymentShippingCountry" = "Country"; +"PaymentShippingZipPlaceholder" = "Postcode"; +"PaymentShippingReceiver" = "Receiver"; +"PaymentShippingName" = "Full Name"; +"PaymentShippingEmailPlaceholder" = "Email"; +"PaymentCheckoutPhoneNumber" = "Phone number"; +"PaymentCheckoutShippingMethod" = "Shipping method"; +"PaymentShippingSave" = "Save Shipping Information"; +"PaymentShippingSaveInfo" = "You can save your shipping info for future use."; +"PaymentInfoHint" = "You paid **%1$s** for **%2$s**."; +"PrivacyPayments" = "Payments"; +"PrivacyPaymentsClearInfo" = "You can delete your shipping info and instruct all payment providers to remove your saved credit cards. Note that Telegram never stores your credit card data."; +"PrivacyPaymentsClear" = "Clear Payment and Shipping Info"; +"PrivacyPaymentsClearAlertTitle" = "Clear payment info"; +"PrivacyPaymentsClearAlertText" = "Are you sure you want to clear your payment and shipping info?"; +"PrivacyPaymentsPaymentInfoCleared" = "Payment info cleared."; +"PrivacyPaymentsShippingInfoCleared" = "Shipping info cleared."; +"PrivacyPaymentsPaymentShippingCleared" = "Payment and shipping info cleared."; +"PrivacyClearShipping" = "Shipping info"; +"PrivacyClearPayment" = "Payment info"; +"Clear" = "Clear"; +"Save" = "Save"; +"PaymentCheckoutName" = "Name"; "AccountSettings.Filters" = "Chat Folders"; "AccountSettings.Notifications" = "Notifications and Sounds"; "AccountSettings.PrivacyAndSecurity" = "Privacy and Security"; @@ -705,6 +774,7 @@ "Chat.Send.WithoutSound" = "Send Without Sound"; "Chat.Send.SetReminder" = "Set a Reminder"; "Chat.Send.ScheduledMessage" = "Schedule Message"; +"Chat.SendAs.PersonalAccount" = "personal account"; "Chat.UnpinAllMessagesConfirmation_one" = "Do you want to unpin %d message in this chat?"; "Chat.UnpinAllMessagesConfirmation_other" = "Do you want to unpin all %d messages in this chat?"; "Chat.Message.Ad.Text" = "Unlike other apps, Telegram never uses your private data to target ads. Sponsored messages on Telegram are based solely on the topic of the public channels in which they are shown. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored messages.\n\nUnlike other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties can’t spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.\n\nTelegram offers a free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible advertisers at:\n\n%@\n\nSponsored Messages are currently in test mode. Once they are fully launched and allow Telegram to cover its basic costs, we will start sharing ad revenue with the owners of public channels in which sponsored messages are displayed.\n\nOnline ads should no longer be synonymous with abuse of user privacy. Let us redefine how a tech company should operate – together."; @@ -713,6 +783,12 @@ "Chat.Message.ViewBot" = "VIEW BOT"; "Chat.Message.ViewGroup" = "VIEW GROUP"; "Chat.Message.Sponsored.What" = "What are sponsored messages?"; +"Checkout.2FA.Text" = "Saving payment details is only available with 2-Step Verification."; +"Checkout.NewCard.CardholderNamePlaceholder" = "Cardholder Name"; +"Checkout.PasswordEntry.Title" = "Payment Confirmation"; +"Checkout.PasswordEntry.Pay" = "Pay"; +"Checkout.PasswordEntry.Text" = "Your card %@ is on file. To pay with this card, please enter your 2-Step-Verification password."; +"Checkout.WebConfirmation.Title" = "Complete Payment"; "ChatList.Context.Mute" = "Mute"; "ChatList.Context.Unmute" = "Unmute"; "ChatList.Context.Pin" = "Pin"; @@ -769,6 +845,7 @@ "Emoji.TravelAndPlaces" = "Travel & Places"; "Emoji.Objects" = "Objects"; "Emoji.Flags" = "Flags"; +"Error.AnError" = "An error occurred. Please try again later."; "FileSize.B" = "%@ B"; "FileSize.KB" = "%@ KB"; "FileSize.MB" = "%@ MB"; @@ -781,6 +858,7 @@ "Message.Context.Pin" = "Pin"; "Message.Context.Unpin" = "Unpin"; "Message.Context.Goto" = "Show Message"; +"Message.ReplyActionButtonShowReceipt" = "Show Receipt"; "MessageContext.CopyMessageLink1" = "Copy Message Link"; "Modal.Send" = "Send"; "NewPoll.Anonymous" = "Anonymous Voting"; @@ -890,6 +968,7 @@ "GeneralSettings.EmojiPrediction" = "Suggest Emoji"; "GroupPermission.Delete" = "Delete Exception"; "Search.Confirm.ClearHistory" = "Are you sure you want to clear your search history?"; +"SecureId.Identity.Placeholder.ExpiryDate" = "Expiry Date"; "Separator.ShowMore" = "show more"; "Separator.ShowLess" = "show less"; "ScheduleController.at" = "at"; @@ -946,7 +1025,6 @@ "VoiceChat.RemovePeer.Confirm" = "Are you sure you want to remove %1$@ from the group?"; "VoiceChat.RemovePeer.Confirm.OK" = "Remove"; "Login.Title" = "Sign in to Telegram"; -"Login.CountrySelectorLabel" = "Country"; "Login.PhoneLabel" = "Phone Number"; "Login.PhoneLabelInvalid" = "Phone Number Invalid"; "Login.KeepSigned" = "Keep me signed in"; @@ -965,6 +1043,7 @@ "FirstName" = "First name (required)"; "LastName" = "Last name (optional)"; "StartMessaging" = "Start Messaging"; +"Country" = "Country"; "Contacts.PhoneNumber.Placeholder" = "Phone Number"; "Login.Next" = "Next"; "Login.ContinueOnLanguage" = "Continue in English"; diff --git a/src/scss/partials/popups/_groupCall.scss b/src/scss/partials/popups/_groupCall.scss index b59056ca..f6c6b66a 100644 --- a/src/scss/partials/popups/_groupCall.scss +++ b/src/scss/partials/popups/_groupCall.scss @@ -74,6 +74,7 @@ &-title, &-subtitle { + font-size: var(--font-size-16); line-height: var(--line-height); @include text-overflow(); diff --git a/src/scss/partials/popups/_popup.scss b/src/scss/partials/popups/_popup.scss index 7a6a9160..d985b230 100644 --- a/src/scss/partials/popups/_popup.scss +++ b/src/scss/partials/popups/_popup.scss @@ -55,7 +55,7 @@ &-title { flex: 1; - padding: 0 2rem 0 1.5rem; + padding: 0 1rem 0 1.5rem; margin: 0; font-size: 1.25rem; font-weight: var(--font-weight-bold);