Localization: Migrate more components (#5484)
This commit is contained in:
parent
cfad59e2f0
commit
8bac803dea
@ -5,14 +5,16 @@ import readFallbackStrings from '../src/util/data/readFallbackStrings';
|
||||
import { pick } from '../src/util/iteratees';
|
||||
|
||||
const HEADER = `/* eslint-disable */
|
||||
// This file is generated by dev/generateInitialLangFallback.ts. Do not edit it manually.\n`;
|
||||
// This file is generated by dev/generateInitialLangFallback.ts. Do not edit it manually.\n
|
||||
import type { LangPackStringValue } from '../../api/types';
|
||||
import type { LangKey } from '../../types/language';\n`;
|
||||
|
||||
async function main() {
|
||||
const data = await readFallbackStrings(true);
|
||||
|
||||
const selectedKeys = pick(data.langPack.strings, initialKeys);
|
||||
const json = JSON.stringify(selectedKeys, undefined, 2);
|
||||
const text = `${HEADER}\nexport default ${json} as Record<string, string>;\n`;
|
||||
const text = `${HEADER}\nexport default ${json} as Record<LangKey, LangPackStringValue>;\n`;
|
||||
writeFileSync('./src/assets/localization/initialStrings.ts', text, 'utf8');
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { FloodWaitError, RPCError } from '../../../lib/gramjs/errors';
|
||||
|
||||
import type { RegularLangKey } from '../../../types/language';
|
||||
import type { RegularLangFnParameters } from '../../../util/localization';
|
||||
import type {
|
||||
ApiUpdateAuthorizationState,
|
||||
ApiUpdateAuthorizationStateType,
|
||||
@ -10,12 +12,12 @@ import type {
|
||||
import { DEBUG } from '../../../config';
|
||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||
|
||||
const ApiErrors: { [k: string]: string } = {
|
||||
PHONE_NUMBER_INVALID: 'Invalid phone number.',
|
||||
PHONE_CODE_INVALID: 'Invalid code.',
|
||||
PASSWORD_HASH_INVALID: 'Incorrect password.',
|
||||
PHONE_PASSWORD_FLOOD: 'Limit exceeded. Please try again later.',
|
||||
PHONE_NUMBER_BANNED: 'This phone number is banned.',
|
||||
const ApiErrors: Record<string, RegularLangKey> = {
|
||||
PHONE_NUMBER_INVALID: 'ErrorPhoneNumberInvalid',
|
||||
PHONE_CODE_INVALID: 'ErrorCodeInvalid',
|
||||
PASSWORD_HASH_INVALID: 'ErrorIncorrectPassword',
|
||||
PHONE_PASSWORD_FLOOD: 'ErrorPasswordFlood',
|
||||
PHONE_NUMBER_BANNED: 'ErrorPhoneBanned',
|
||||
};
|
||||
|
||||
const authController: {
|
||||
@ -85,19 +87,30 @@ export function onRequestQrCode(qrCode: { token: Buffer; expires: number }) {
|
||||
}
|
||||
|
||||
export function onAuthError(err: Error) {
|
||||
let message: string;
|
||||
let messageKey: RegularLangFnParameters | undefined;
|
||||
|
||||
if (err instanceof FloodWaitError) {
|
||||
const hours = Math.ceil(Number(err.seconds) / 60 / 60);
|
||||
message = `Too many attempts. Try again in ${hours > 1 ? `${hours} hours` : 'an hour'}`;
|
||||
messageKey = {
|
||||
key: 'ErrorFlood',
|
||||
variables: { hour: hours },
|
||||
options: { pluralValue: hours },
|
||||
};
|
||||
} else if (err instanceof RPCError) {
|
||||
message = ApiErrors[err.errorMessage];
|
||||
} else {
|
||||
message = err.message;
|
||||
messageKey = {
|
||||
key: ApiErrors[err.errorMessage],
|
||||
};
|
||||
} else if (err.message) {
|
||||
messageKey = {
|
||||
key: 'ErrorUnexpectedMessage',
|
||||
variables: { error: err.message },
|
||||
};
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
message = 'Unexpected Error';
|
||||
if (!messageKey) {
|
||||
messageKey = {
|
||||
key: 'ErrorUnexpected',
|
||||
};
|
||||
|
||||
if (DEBUG) {
|
||||
// eslint-disable-next-line no-console
|
||||
@ -107,7 +120,7 @@ export function onAuthError(err: Error) {
|
||||
|
||||
sendApiUpdate({
|
||||
'@type': 'updateAuthorizationError',
|
||||
message,
|
||||
errorKey: messageKey,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -17,8 +17,8 @@ import type {
|
||||
import {
|
||||
ACCEPTABLE_USERNAME_ERRORS,
|
||||
BLOCKED_LIST_LIMIT,
|
||||
LANG_PACK,
|
||||
MAX_INT_32,
|
||||
OLD_DEFAULT_LANG_PACK,
|
||||
} from '../../../config';
|
||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||
import { getServerTime } from '../../../util/serverTime';
|
||||
@ -36,7 +36,6 @@ import {
|
||||
buildApiWebSession,
|
||||
buildLangStrings,
|
||||
oldBuildLangPack,
|
||||
oldBuildLangPackString,
|
||||
} from '../apiBuilders/misc';
|
||||
import { getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
import {
|
||||
@ -468,7 +467,7 @@ export async function fetchLangDifference({
|
||||
|
||||
export async function fetchLanguages(): Promise<ApiLanguage[] | undefined> {
|
||||
const result = await invokeRequest(new GramJs.langpack.GetLanguages({
|
||||
langPack: OLD_DEFAULT_LANG_PACK,
|
||||
langPack: LANG_PACK,
|
||||
}));
|
||||
if (!result) {
|
||||
return undefined;
|
||||
@ -495,6 +494,27 @@ export async function fetchLanguage({
|
||||
return buildApiLanguage(result);
|
||||
}
|
||||
|
||||
export async function fetchLangStrings({
|
||||
langPack,
|
||||
langCode,
|
||||
keys,
|
||||
}: {
|
||||
langPack: string;
|
||||
langCode: string;
|
||||
keys: string[];
|
||||
}) {
|
||||
const result = await invokeRequest(new GramJs.langpack.GetStrings({
|
||||
langPack,
|
||||
langCode,
|
||||
keys,
|
||||
}));
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return buildLangStrings(result);
|
||||
}
|
||||
|
||||
export async function oldFetchLangPack({ sourceLangPacks, langCode }: {
|
||||
sourceLangPacks: typeof LANG_PACKS;
|
||||
langCode: string;
|
||||
@ -514,22 +534,6 @@ export async function oldFetchLangPack({ sourceLangPacks, langCode }: {
|
||||
return { langPack: Object.assign({}, ...collections.reverse()) as typeof collections[0] };
|
||||
}
|
||||
|
||||
export async function oldFetchLangStrings({ langPack, langCode, keys }: {
|
||||
langPack: string; langCode: string; keys: string[];
|
||||
}) {
|
||||
const result = await invokeRequest(new GramJs.langpack.GetStrings({
|
||||
langPack,
|
||||
langCode: BETA_LANG_CODES.includes(langCode) ? `${langCode}-raw` : langCode,
|
||||
keys,
|
||||
}));
|
||||
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return result.map(oldBuildLangPackString);
|
||||
}
|
||||
|
||||
export async function fetchPrivacySettings(privacyKey: ApiPrivacyKey) {
|
||||
const key = buildInputPrivacyKey(privacyKey);
|
||||
const result = await invokeRequest(new GramJs.account.GetPrivacy({ key }));
|
||||
|
||||
@ -7,6 +7,7 @@ import type {
|
||||
VideoState,
|
||||
} from '../../lib/secret-sauce';
|
||||
import type { ThreadId } from '../../types';
|
||||
import type { RegularLangFnParameters } from '../../util/localization';
|
||||
import type { ApiBotMenuButton } from './bots';
|
||||
import type {
|
||||
ApiGroupCall, ApiPhoneCall,
|
||||
@ -84,7 +85,7 @@ export type ApiUpdateSession = {
|
||||
|
||||
export type ApiUpdateAuthorizationError = {
|
||||
'@type': 'updateAuthorizationError';
|
||||
message: string;
|
||||
errorKey: RegularLangFnParameters;
|
||||
};
|
||||
|
||||
export type ApiUpdateConnectionState = {
|
||||
|
||||
@ -162,7 +162,7 @@
|
||||
"LoginQRLogin" = "Log in by QR Code";
|
||||
"LoginQRTitle" = "Log in to Telegram by QR Code";
|
||||
"LoginQRHelp1" = "Open Telegram on your phone";
|
||||
"LoginQR2Help2" = "Go to **Settings** > **Devices** > **Link Desktop Device**";
|
||||
"LoginQRHelp2" = "Go to **Settings** > **Devices** > **Link Desktop Device**";
|
||||
"LoginQRHelp3" = "Point your phone at this screen to confirm login";
|
||||
"LoginQRCancel" = "Log in by phone Number";
|
||||
"YourName" = "Your Name";
|
||||
@ -394,6 +394,8 @@
|
||||
"AuthSessionsViewBrowser" = "Browser";
|
||||
"AuthSessionsViewLocationInfo" = "This location estimate is based on the IP address and may not always be accurate.";
|
||||
"AuthSessionsLogOutApplications" = "Disconnect All Websites";
|
||||
"AuthKeepSignedIn" = "Keep me signed in";
|
||||
"AuthTitle" = "Telegram";
|
||||
"ClearOtherWebSessionsHelp" = "You can log in on websites that support signing in with Telegram.";
|
||||
"AreYouSureWebSessions" = "Are you sure you want to disconnect all websites where you logged in with Telegram?";
|
||||
"AutodownloadSizeLimitUpTo" = "up to {limit}";
|
||||
@ -421,10 +423,17 @@
|
||||
"SettingsSendEnter" = "Send with Enter";
|
||||
"SettingsSendCmdenter" = "Send with Cmd+Enter";
|
||||
"SettingsSendCtrlenter" = "Send with Ctrl+Enter";
|
||||
"SettingsSendEnterDescription" = "New line by Shift + Enter";
|
||||
"SettingsSendPlusEnterDescription" = "New line by Enter";
|
||||
"SettingsTimeFormat" = "Time Format";
|
||||
"SettingsTimeFormat12" = "12-hour";
|
||||
"SettingsTimeFormat24" = "24-hour";
|
||||
"SettingsKeyboard" = "Keyboard";
|
||||
"SettingsTray" = "Show Icon in Menu Bar";
|
||||
"SettingsOfflineNotificationUnsupported" = "Not supported";
|
||||
"TextSize" = "Message Font Size";
|
||||
"ChatBackground" = "Chat Wallpaper";
|
||||
"Theme" = "Theme";
|
||||
"VoiceOverKeyboard" = "Keyboard";
|
||||
"AccDescrStickers" = "Stickers";
|
||||
"DoubleTapSetting" = "Quick Reaction";
|
||||
"SuggestStickers" = "Sticker suggestions by emoji";
|
||||
@ -625,10 +634,49 @@
|
||||
"PollsSolutionTitle" = "Explanation";
|
||||
"CreatePollExplanationInfo" = "Users will see this comment after choosing a wrong answer, good for educational purposes.";
|
||||
"VoipGroupPersonalAccount" = "personal account";
|
||||
"MenuStickers" = "Stickers and Emoji";
|
||||
"MenuAnimations" = "Animations and Performance";
|
||||
"MenuStars" = "My Stars";
|
||||
"MenuSendGift" = "Send a Gift";
|
||||
"MenuTelegramFaq" = "Telegram FAQ";
|
||||
"MenuPrivacyPolicy" = "Privacy Policy";
|
||||
"MenuAskText" = "Please note that Telegram Support is done by volunteers. We try to respond as quickly as possible, but it may take a while.\n\nPlease take a look at the Telegram FAQ: it has important troubleshooting tips and answers to most questions.";
|
||||
"SettingsPerformanceSliderTitle" = "Animation Level";
|
||||
"SettingsPerformanceSliderSubtitle" = "Choose the desired animations amount.";
|
||||
"SettingsPerformanceSliderLow" = "Power Saving";
|
||||
"SettingsPerformanceSliderMedium" = "Nice and Fast";
|
||||
"SettingsPerformanceSliderCustom" = "Custom";
|
||||
"SettingsPerformanceSliderHigh" = "Lots of Stuff";
|
||||
"SettingsPerformanceInterfaceAnimations" = "Interface Animations";
|
||||
"SettingsPerformanceStickers" = "Stickers and Emoji";
|
||||
"SettingsPerformanceMediaAutoplay" = "Media Autoplay";
|
||||
"SettingsPerformancePageTransitions" = "Page Transitions";
|
||||
"SettingsPerformanceSending" = "Message Sending Animation";
|
||||
"SettingsPerformanceMediaViewer" = "Media Viewer Animations";
|
||||
"SettingsPerformanceComposer" = "Message Composer Animations";
|
||||
"SettingsPerformanceContextAnimation" = "Context Menu Animation";
|
||||
"SettingsPerformanceContextBlur" = "Context Menu Blur";
|
||||
"SettingsPerformanceRightColumn" = "Right Column Animation";
|
||||
"SettingsPerformanceThanos" = "Dust-effect deletion";
|
||||
"SettingsPerformanceAnimatedEmoji" = "Allow Animated Emoji";
|
||||
"SettingsPerformanceLoopStickers" = "Loop Animated Stickers";
|
||||
"SettingsPerformanceReactionEffects" = "Reaction Effects";
|
||||
"SettingsPerformanceStickerEffects" = "Sticker Effects";
|
||||
"SettingsPerformanceAutoplayGif" = "Autoplay GIFs";
|
||||
"SettingsPerformanceAutoplayVideo" = "Autoplay Videos";
|
||||
"FavoriteStickers" = "Favorites";
|
||||
"PremiumStickers" = "Premium Stickers";
|
||||
"GroupStickers" = "Group Stickers";
|
||||
"ErrorSendRestrictedStickersAll" = "Sorry, sending stickers is not allowed in this group.";
|
||||
"ErrorPhoneNumberInvalid" = "Invalid phone number, please try again.";
|
||||
"ErrorCodeInvalid" = "Invalid code, please try again.";
|
||||
"ErrorIncorrectPassword" = "Invalid password, please try again.";
|
||||
"ErrorPasswordFlood" = "Too many attempts, please try again later.";
|
||||
"ErrorPhoneBanned" = "This phone number is banned.";
|
||||
"ErrorFlood_one" = "Too many attempts, please try again in {hour} hour";
|
||||
"ErrorFlood_other" = "Too many attempts, please try again in {hour} hours";
|
||||
"ErrorUnexpected" = "Unexpected error";
|
||||
"ErrorUnexpectedMessage" = "Unexpected error: {error}";
|
||||
"NoStickers" = "No stickers yet";
|
||||
"ClearRecentEmoji" = "Clear recent emoji?";
|
||||
"TextFormatAddLinkTitle" = "Add Link";
|
||||
@ -1343,8 +1391,8 @@
|
||||
"GiftInfoConvertTitle" = "Convert Gift to Stars";
|
||||
"GiftInfoConvertDescription1" = "Do you want to convert this gift from **{user}** to **{amount}**?";
|
||||
"GiftInfoConvertDescription2" = "This action cannot be undone. This will permanently destroy the gift.";
|
||||
"GiftInfoConvertDescriptionPeriod_one" = "Conversion is available for the next **{count} days**."
|
||||
"GiftInfoConvertDescriptionPeriod_other" = "Conversion is available for the next **{count} days**."
|
||||
"GiftInfoConvertDescriptionPeriod_one" = "Conversion is available for the next **{count} days**.";
|
||||
"GiftInfoConvertDescriptionPeriod_other" = "Conversion is available for the next **{count} days**.";
|
||||
"GiftInfoSaved" = "This gift is visible on your profile. {link}";
|
||||
"GiftInfoSavedView" = "View >";
|
||||
"GiftInfoHidden" = "This gift is hidden. Only you can see it.";
|
||||
@ -1363,10 +1411,10 @@
|
||||
"GiftAttributeModel" = "Model";
|
||||
"GiftAttributeBackdrop" = "Backdrop";
|
||||
"GiftAttributeSymbol" = "Symbol";
|
||||
"GiftInfoOriginalInfo" = "Gifted to {user} on {date}."
|
||||
"GiftInfoOriginalInfoSender" = "Gifted by {sender} to {user} on {date}."
|
||||
"GiftInfoOriginalInfoText" = "Gifted to {user} on {date} with comment \"{text}\"."
|
||||
"GiftInfoOriginalInfoTextSender" = "Gifted by {sender} to {user} on {date} with comment \"{text}\"."
|
||||
"GiftInfoOriginalInfo" = "Gifted to {user} on {date}.";
|
||||
"GiftInfoOriginalInfoSender" = "Gifted by {sender} to {user} on {date}.";
|
||||
"GiftInfoOriginalInfoText" = "Gifted to {user} on {date} with comment \"{text}\".";
|
||||
"GiftInfoOriginalInfoTextSender" = "Gifted by {sender} to {user} on {date} with comment \"{text}\".";
|
||||
"GiftInfoStatus" = "Status";
|
||||
"GiftInfoStatusNonUnique" = "Non-Unique";
|
||||
"GiftInfoViewUpgraded" = "View Upgraded Gift";
|
||||
@ -1399,7 +1447,7 @@
|
||||
"ReceivedGift" = "Received Gift";
|
||||
"SentGift" = "Sent Gift";
|
||||
"StarGiftInfoDescriptionInbound" = "You can keep this gift in your Profile or convert it to {count} Stars. {link}";
|
||||
"StarGiftInfoDescriptionOutgoing" = "{user} can keep this gift in Profile or convert it to {count} Stars. {link}"
|
||||
"StarGiftInfoDescriptionOutgoing" = "{user} can keep this gift in Profile or convert it to {count} Stars. {link}";
|
||||
"StarGiftInfoLinkCaption" = "More About Stars >";
|
||||
"StarGiftDisplayOnMyPage" = "Display on on my page";
|
||||
"StarGiftConvertTo" = "Convert to";
|
||||
@ -1435,12 +1483,12 @@
|
||||
"BotDownloadFileDescription" = "**{bot}** suggests you to download **{filename}**";
|
||||
"BotDownloadFileButton" = "Download";
|
||||
"PrivacyGifts" = "Gifts";
|
||||
"PrivacyGiftsTitle" = "Who can display gifts on my profile?"
|
||||
"PrivacyGiftsInfo" = "Choose whether gifts from specific senders need your approval before they're visible to others on your profile."
|
||||
"PrivacyValueBots" = "Mini Apps"
|
||||
"CustomShareGiftsInfo" = "You can add users or entire groups as exceptions that will override the settings above."
|
||||
"StarsSubscribeBotText_one" = "Do you want to subscribe to **{name}** in **{bot}** for **{amount}** star per month?"
|
||||
"StarsSubscribeBotText_other" = "Do you want to subscribe to **{name}** in **{bot}** for **{amount}** stars per month?"
|
||||
"PrivacyGiftsTitle" = "Who can display gifts on my profile?";
|
||||
"PrivacyGiftsInfo" = "Choose whether gifts from specific senders need your approval before they're visible to others on your profile.";
|
||||
"PrivacyValueBots" = "Mini Apps";
|
||||
"CustomShareGiftsInfo" = "You can add users or entire groups as exceptions that will override the settings above.";
|
||||
"StarsSubscribeBotText_one" = "Do you want to subscribe to **{name}** in **{bot}** for **{amount}** star per month?";
|
||||
"StarsSubscribeBotText_other" = "Do you want to subscribe to **{name}** in **{bot}** for **{amount}** stars per month?";
|
||||
"StarsSubscribeBotButtonMonth" = "Subscribe for {amount} / month";
|
||||
"AllChatsSearchContext" = "All Chats";
|
||||
"PrivateChatsSearchContext" = "Private Chats";
|
||||
@ -1450,9 +1498,9 @@
|
||||
"FolderLinkTitleDescription" = "Anyone with this link can add {folder} folder and {chats} selected below.";
|
||||
"FolderLinkTitleDescriptionChats_one" = "the chat";
|
||||
"FolderLinkTitleDescriptionChats_other" = "the {count} chats";
|
||||
"FolderLinkSubtitleNew" = "Do you want to add a new chat folder and join its groups and channels?"
|
||||
"FolderLinkSubtitleAlready" = "You have already added this folder and its chats."
|
||||
"FolderLinkSubtitleAdd" = "Do you want to add {chats} to the folder **{title}**?"
|
||||
"FolderLinkSubtitleNew" = "Do you want to add a new chat folder and join its groups and channels?";
|
||||
"FolderLinkSubtitleAlready" = "You have already added this folder and its chats.";
|
||||
"FolderLinkSubtitleAdd" = "Do you want to add {chats} to the folder **{title}**?";
|
||||
"FolderLinkSubtitleAddCount_one" = "1 chat";
|
||||
"FolderLinkSubtitleAddCount_other" = "{count} chats";
|
||||
"FolderLinkAddFolder" = "Add Folder";
|
||||
@ -1496,7 +1544,7 @@
|
||||
"ActionUnsupportedDescription" = "Please, use one of our apps to complete this action.";
|
||||
"LocationPermissionText" = "**{name}** requests access to set your **location**. You will be able to revoke this access in the profile page of **{name}**.";
|
||||
"UnlockMoreSimilarBots" = "Show More Apps";
|
||||
"MoreSimilarBotsText" = "Subscribe to **Telegram Premium** to unlock up to {count} similar apps."
|
||||
"MoreSimilarBotsText" = "Subscribe to **Telegram Premium** to unlock up to {count} similar apps.";
|
||||
"GiftWasNotFound" = "Gift was not found";
|
||||
"ViewButtonRequestJoin" = "REQUEST TO JOIN";
|
||||
"ViewButtonMessage" = "VIEW MESSAGE";
|
||||
@ -1511,4 +1559,5 @@
|
||||
"ViewButtonStory" = "VIEW STORY";
|
||||
"ViewButtonBoost" = "BOOST";
|
||||
"ViewButtonStickerset" = "VIEW STICKERS";
|
||||
"ViewButtonGiftUnique" = "VIEW COLLECTIBLE";
|
||||
"ViewButtonGiftUnique" = "VIEW COLLECTIBLE";
|
||||
"AuthContinueOnThisLanguage" = "Continue in English";
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
const INITIAL_KEYS = [
|
||||
import type { LangKey } from '../../types/language';
|
||||
|
||||
const INITIAL_KEYS: LangKey[] = [
|
||||
'WrongNumber',
|
||||
'SentAppCode',
|
||||
'LoginJustSentSms',
|
||||
@ -11,7 +13,7 @@ const INITIAL_KEYS = [
|
||||
'LoginQRTitle',
|
||||
'LoginQRHelp1',
|
||||
'LoginQRHelp2',
|
||||
'LoginQR2Help2',
|
||||
'LoginQRHelp2',
|
||||
'LoginQRHelp3',
|
||||
'LoginQRCancel',
|
||||
'YourName',
|
||||
@ -21,6 +23,14 @@ const INITIAL_KEYS = [
|
||||
'LoginSelectCountryTitle',
|
||||
'CountryNone',
|
||||
'PleaseEnterPassword',
|
||||
'ErrorPhoneNumberInvalid',
|
||||
'ErrorCodeInvalid',
|
||||
'ErrorIncorrectPassword',
|
||||
'ErrorPasswordFlood',
|
||||
'ErrorPhoneBanned',
|
||||
'ErrorFlood',
|
||||
'ErrorUnexpected',
|
||||
'ErrorUnexpectedMessage',
|
||||
];
|
||||
|
||||
export default INITIAL_KEYS;
|
||||
|
||||
@ -1,19 +1,22 @@
|
||||
/* eslint-disable */
|
||||
// This file is generated by dev/generateInitialLangFallback.ts. Do not edit it manually.
|
||||
|
||||
import type { LangPackStringValue } from '../../api/types';
|
||||
import type { LangKey } from '../../types/language';
|
||||
|
||||
export default {
|
||||
"WrongNumber": "Wrong number?",
|
||||
"SentAppCode": "We've sent the code to the **Telegram** app on your other device.",
|
||||
"LoginJustSentSms": "We've sent you a code via SMS. Please enter it above.",
|
||||
"LoginHeaderPassword": "Enter Password",
|
||||
"LoginEnterPasswordDescription": "You have Two-Step Verification enabled, so your account is protected with an additional password.",
|
||||
"StartText": "Please confirm your country codenand enter your phone number.",
|
||||
"StartText": "Please confirm your country code\nand enter your phone number.",
|
||||
"LoginPhonePlaceholder": "Your phone number",
|
||||
"LoginNext": "Next",
|
||||
"LoginQRLogin": "Log in by QR Code",
|
||||
"LoginQRTitle": "Log in to Telegram by QR Code",
|
||||
"LoginQRHelp1": "Open Telegram on your phone",
|
||||
"LoginQR2Help2": "Go to **Settings** > **Devices** > **Link Desktop Device**",
|
||||
"LoginQRHelp2": "Go to **Settings** > **Devices** > **Link Desktop Device**",
|
||||
"LoginQRHelp3": "Point your phone at this screen to confirm login",
|
||||
"LoginQRCancel": "Log in by phone Number",
|
||||
"YourName": "Your Name",
|
||||
@ -22,5 +25,16 @@ export default {
|
||||
"LoginRegisterLastNamePlaceholder": "Last Name",
|
||||
"LoginSelectCountryTitle": "Country",
|
||||
"CountryNone": "Country not found",
|
||||
"PleaseEnterPassword": "Enter your new password"
|
||||
} as Record<string, string>;
|
||||
"PleaseEnterPassword": "Enter your new password",
|
||||
"ErrorPhoneNumberInvalid": "Invalid phone number, please try again.",
|
||||
"ErrorCodeInvalid": "Invalid code, please try again.",
|
||||
"ErrorIncorrectPassword": "Invalid password, please try again.",
|
||||
"ErrorPasswordFlood": "Too many attempts, please try again later.",
|
||||
"ErrorPhoneBanned": "This phone number is banned.",
|
||||
"ErrorFlood": {
|
||||
"one": "Too many attempts, please try again in {hour} hour",
|
||||
"other": "Too many attempts, please try again in {hour} hours"
|
||||
},
|
||||
"ErrorUnexpected": "Unexpected error",
|
||||
"ErrorUnexpectedMessage": "Unexpected error: {error}"
|
||||
} as Record<LangKey, LangPackStringValue>;
|
||||
|
||||
@ -9,16 +9,16 @@ import type { GlobalState } from '../../global/types';
|
||||
|
||||
import { pick } from '../../util/iteratees';
|
||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
|
||||
import useHistoryBack from '../../hooks/useHistoryBack';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import useLang from '../../hooks/useLang';
|
||||
|
||||
import Icon from '../common/icons/Icon';
|
||||
import TrackingMonkey from '../common/TrackingMonkey';
|
||||
import InputText from '../ui/InputText';
|
||||
import Loading from '../ui/Loading';
|
||||
|
||||
type StateProps = Pick<GlobalState, 'authPhoneNumber' | 'authIsCodeViaApp' | 'authIsLoading' | 'authError'>;
|
||||
type StateProps = Pick<GlobalState, 'authPhoneNumber' | 'authIsCodeViaApp' | 'authIsLoading' | 'authErrorKey'>;
|
||||
|
||||
const CODE_LENGTH = 5;
|
||||
|
||||
@ -26,15 +26,15 @@ const AuthCode: FC<StateProps> = ({
|
||||
authPhoneNumber,
|
||||
authIsCodeViaApp,
|
||||
authIsLoading,
|
||||
authError,
|
||||
authErrorKey,
|
||||
}) => {
|
||||
const {
|
||||
setAuthCode,
|
||||
returnToAuthPhoneNumber,
|
||||
clearAuthError,
|
||||
clearAuthErrorKey,
|
||||
} = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@ -54,8 +54,8 @@ const AuthCode: FC<StateProps> = ({
|
||||
});
|
||||
|
||||
const onCodeChange = useCallback((e: FormEvent<HTMLInputElement>) => {
|
||||
if (authError) {
|
||||
clearAuthError();
|
||||
if (authErrorKey) {
|
||||
clearAuthErrorKey();
|
||||
}
|
||||
|
||||
const { currentTarget: target } = e;
|
||||
@ -82,7 +82,7 @@ const AuthCode: FC<StateProps> = ({
|
||||
if (target.value.length === CODE_LENGTH) {
|
||||
setAuthCode({ code: target.value });
|
||||
}
|
||||
}, [authError, clearAuthError, code, isTracking, setAuthCode]);
|
||||
}, [authErrorKey, code, isTracking, setAuthCode]);
|
||||
|
||||
function handleReturnToAuthPhoneNumber() {
|
||||
returnToAuthPhoneNumber();
|
||||
@ -107,11 +107,14 @@ const AuthCode: FC<StateProps> = ({
|
||||
title={lang('WrongNumber')}
|
||||
aria-label={lang('WrongNumber')}
|
||||
>
|
||||
<i className="icon icon-edit" />
|
||||
<Icon name="edit" />
|
||||
</div>
|
||||
</h1>
|
||||
<p className="note">
|
||||
{renderText(lang(authIsCodeViaApp ? 'SentAppCode' : 'Login.JustSentSms'), ['simple_markdown'])}
|
||||
{lang(authIsCodeViaApp ? 'SentAppCode' : 'LoginJustSentSms', undefined, {
|
||||
withNodes: true,
|
||||
withMarkdown: true,
|
||||
})}
|
||||
</p>
|
||||
<InputText
|
||||
ref={inputRef}
|
||||
@ -119,7 +122,7 @@ const AuthCode: FC<StateProps> = ({
|
||||
label={lang('Code')}
|
||||
onInput={onCodeChange}
|
||||
value={code}
|
||||
error={authError && lang(authError)}
|
||||
error={authErrorKey && lang.withRegular(authErrorKey)}
|
||||
autoComplete="off"
|
||||
inputMode="numeric"
|
||||
/>
|
||||
@ -130,5 +133,5 @@ const AuthCode: FC<StateProps> = ({
|
||||
};
|
||||
|
||||
export default memo(withGlobal(
|
||||
(global): StateProps => pick(global, ['authPhoneNumber', 'authIsCodeViaApp', 'authIsLoading', 'authError']),
|
||||
(global): StateProps => pick(global, ['authPhoneNumber', 'authIsCodeViaApp', 'authIsLoading', 'authErrorKey']),
|
||||
)(AuthCode));
|
||||
|
||||
@ -6,19 +6,19 @@ import type { GlobalState } from '../../global/types';
|
||||
|
||||
import { pick } from '../../util/iteratees';
|
||||
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import useLang from '../../hooks/useLang';
|
||||
|
||||
import PasswordForm from '../common/PasswordForm';
|
||||
import MonkeyPassword from '../common/PasswordMonkey';
|
||||
|
||||
type StateProps = Pick<GlobalState, 'authIsLoading' | 'authError' | 'authHint'>;
|
||||
type StateProps = Pick<GlobalState, 'authIsLoading' | 'authErrorKey' | 'authHint'>;
|
||||
|
||||
const AuthPassword: FC<StateProps> = ({
|
||||
authIsLoading, authError, authHint,
|
||||
authIsLoading, authErrorKey, authHint,
|
||||
}) => {
|
||||
const { setAuthPassword, clearAuthError } = getActions();
|
||||
const { setAuthPassword, clearAuthErrorKey } = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const handleChangePasswordVisibility = useCallback((isVisible) => {
|
||||
@ -33,11 +33,11 @@ const AuthPassword: FC<StateProps> = ({
|
||||
<div id="auth-password-form" className="custom-scroll">
|
||||
<div className="auth-form">
|
||||
<MonkeyPassword isPasswordVisible={showPassword} />
|
||||
<h1>{lang('Login.Header.Password')}</h1>
|
||||
<p className="note">{lang('Login.EnterPasswordDescription')}</p>
|
||||
<h1>{lang('LoginHeaderPassword')}</h1>
|
||||
<p className="note">{lang('LoginEnterPasswordDescription')}</p>
|
||||
<PasswordForm
|
||||
clearError={clearAuthError}
|
||||
error={authError && lang(authError)}
|
||||
clearError={clearAuthErrorKey}
|
||||
error={authErrorKey && lang.withRegular(authErrorKey)}
|
||||
hint={authHint}
|
||||
isLoading={authIsLoading}
|
||||
isPasswordVisible={showPassword}
|
||||
@ -50,5 +50,5 @@ const AuthPassword: FC<StateProps> = ({
|
||||
};
|
||||
|
||||
export default memo(withGlobal(
|
||||
(global): StateProps => pick(global, ['authIsLoading', 'authError', 'authHint']),
|
||||
(global): StateProps => pick(global, ['authIsLoading', 'authErrorKey', 'authHint']),
|
||||
)(AuthPassword));
|
||||
|
||||
@ -18,8 +18,8 @@ import { IS_SAFARI, IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
||||
import { getSuggestedLanguage } from './helpers/getSuggestedLanguage';
|
||||
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import useOldLangString from '../../hooks/useOldLangString';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useLangString from '../../hooks/useLangString';
|
||||
|
||||
import Button from '../ui/Button';
|
||||
import Checkbox from '../ui/Checkbox';
|
||||
@ -32,7 +32,7 @@ import monkeyPath from '../../assets/monkey.svg';
|
||||
type StateProps = Pick<GlobalState, (
|
||||
'connectionState' | 'authState' |
|
||||
'authPhoneNumber' | 'authIsLoading' |
|
||||
'authIsLoadingQrCode' | 'authError' |
|
||||
'authIsLoadingQrCode' | 'authErrorKey' |
|
||||
'authRememberMe' | 'authNearestCountry'
|
||||
)> & {
|
||||
language?: string;
|
||||
@ -49,7 +49,7 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
||||
authPhoneNumber,
|
||||
authIsLoading,
|
||||
authIsLoadingQrCode,
|
||||
authError,
|
||||
authErrorKey,
|
||||
authRememberMe,
|
||||
authNearestCountry,
|
||||
phoneCodeList,
|
||||
@ -60,18 +60,18 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
||||
setAuthRememberMe,
|
||||
loadNearestCountry,
|
||||
loadCountryList,
|
||||
clearAuthError,
|
||||
clearAuthErrorKey,
|
||||
goToAuthQrCode,
|
||||
setSettingOption,
|
||||
} = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const suggestedLanguage = getSuggestedLanguage();
|
||||
|
||||
const isConnected = connectionState === 'connectionStateReady';
|
||||
const continueText = useOldLangString(isConnected ? suggestedLanguage : undefined, 'ContinueOnThisLanguage', true);
|
||||
const continueText = useLangString('AuthContinueOnThisLanguage', suggestedLanguage);
|
||||
const [country, setCountry] = useState<ApiCountryCode | undefined>();
|
||||
const [phoneNumber, setPhoneNumber] = useState<string | undefined>();
|
||||
const [isTouched, setIsTouched] = useState(false);
|
||||
@ -161,8 +161,8 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
||||
}, []);
|
||||
|
||||
const handlePhoneNumberChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (authError) {
|
||||
clearAuthError();
|
||||
if (authErrorKey) {
|
||||
clearAuthErrorKey();
|
||||
}
|
||||
|
||||
// This is for further screens. We delay it until user input to speed up the initial loading.
|
||||
@ -186,7 +186,7 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
||||
&& value.length - fullNumber.length > 1 && !isJustPastedRef.current
|
||||
);
|
||||
parseFullNumber(shouldFixSafariAutoComplete ? `${country!.countryCode} ${value}` : value);
|
||||
}, [authError, clearAuthError, country, fullNumber, parseFullNumber]);
|
||||
}, [authErrorKey, country, fullNumber, parseFullNumber]);
|
||||
|
||||
const handleKeepSessionChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||
setAuthRememberMe(e.target.checked);
|
||||
@ -214,7 +214,7 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
||||
<div id="auth-phone-number-form" className="custom-scroll">
|
||||
<div className="auth-form">
|
||||
<div id="logo" />
|
||||
<h1>Telegram</h1>
|
||||
<h1>{lang('AuthTitle')}</h1>
|
||||
<p className="note">{lang('StartText')}</p>
|
||||
<form className="form" action="" onSubmit={handleSubmit}>
|
||||
<CountryCodeInput
|
||||
@ -226,29 +226,29 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
||||
<InputText
|
||||
ref={inputRef}
|
||||
id="sign-in-phone-number"
|
||||
label={lang('Login.PhonePlaceholder')}
|
||||
label={lang('LoginPhonePlaceholder')}
|
||||
value={fullNumber}
|
||||
error={authError && lang(authError)}
|
||||
error={authErrorKey && lang.withRegular(authErrorKey)}
|
||||
inputMode="tel"
|
||||
onChange={handlePhoneNumberChange}
|
||||
onPaste={IS_SAFARI ? handlePaste : undefined}
|
||||
/>
|
||||
<Checkbox
|
||||
id="sign-in-keep-session"
|
||||
label="Keep me signed in"
|
||||
label={lang('AuthKeepSignedIn')}
|
||||
checked={Boolean(authRememberMe)}
|
||||
onChange={handleKeepSessionChange}
|
||||
/>
|
||||
{canSubmit && (
|
||||
isAuthReady ? (
|
||||
<Button type="submit" ripple isLoading={authIsLoading}>{lang('Login.Next')}</Button>
|
||||
<Button type="submit" ripple isLoading={authIsLoading}>{lang('LoginNext')}</Button>
|
||||
) : (
|
||||
<Loading />
|
||||
)
|
||||
)}
|
||||
{isAuthReady && (
|
||||
<Button isText ripple isLoading={authIsLoadingQrCode} onClick={handleGoToAuthQrCode}>
|
||||
{lang('Login.QR.Login')}
|
||||
{lang('LoginQRLogin')}
|
||||
</Button>
|
||||
)}
|
||||
{suggestedLanguage && suggestedLanguage !== language && continueText && (
|
||||
@ -274,7 +274,7 @@ export default memo(withGlobal(
|
||||
'authPhoneNumber',
|
||||
'authIsLoading',
|
||||
'authIsLoadingQrCode',
|
||||
'authError',
|
||||
'authErrorKey',
|
||||
'authRememberMe',
|
||||
'authNearestCountry',
|
||||
]),
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React, {
|
||||
memo, useCallback, useEffect, useLayoutEffect, useRef,
|
||||
} from '../../lib/teact/teact';
|
||||
@ -11,14 +10,13 @@ import { disableStrict, enableStrict } from '../../lib/fasterdom/stricterdom';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { oldSetLanguage } from '../../util/oldLangProvider';
|
||||
import { LOCAL_TGS_URLS } from '../common/helpers/animatedAssets';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
import { getSuggestedLanguage } from './helpers/getSuggestedLanguage';
|
||||
|
||||
import useAsync from '../../hooks/useAsync';
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useLangString from '../../hooks/useLangString';
|
||||
import useMediaTransitionDeprecated from '../../hooks/useMediaTransitionDeprecated';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import useOldLangString from '../../hooks/useOldLangString';
|
||||
|
||||
import AnimatedIcon from '../common/AnimatedIcon';
|
||||
import Button from '../ui/Button';
|
||||
@ -44,24 +42,24 @@ function ensureQrCodeStyling() {
|
||||
return qrCodeStylingPromise;
|
||||
}
|
||||
|
||||
const AuthCode: FC<StateProps> = ({
|
||||
const AuthCode = ({
|
||||
connectionState,
|
||||
authState,
|
||||
authQrCode,
|
||||
language,
|
||||
}) => {
|
||||
}: StateProps) => {
|
||||
const {
|
||||
returnToAuthPhoneNumber,
|
||||
setSettingOption,
|
||||
} = getActions();
|
||||
|
||||
const suggestedLanguage = getSuggestedLanguage();
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const qrCodeRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isConnected = connectionState === 'connectionStateReady';
|
||||
const continueText = useOldLangString(isConnected ? suggestedLanguage : undefined, 'ContinueOnThisLanguage', true);
|
||||
const continueText = useLangString('AuthContinueOnThisLanguage', suggestedLanguage);
|
||||
const [isLoading, markIsLoading, unmarkIsLoading] = useFlag();
|
||||
const [isQrMounted, markQrMounted, unmarkQrMounted] = useFlag();
|
||||
|
||||
@ -173,14 +171,14 @@ const AuthCode: FC<StateProps> = ({
|
||||
</div>
|
||||
{!isQrMounted && <div className="qr-loading"><Loading /></div>}
|
||||
</div>
|
||||
<h1>{lang('Login.QR.Title')}</h1>
|
||||
<h1>{lang('LoginQRTitle')}</h1>
|
||||
<ol>
|
||||
<li><span>{lang('Login.QR.Help1')}</span></li>
|
||||
<li><span>{renderText(lang('Login.QR2.Help2'), ['simple_markdown'])}</span></li>
|
||||
<li><span>{lang('Login.QR.Help3')}</span></li>
|
||||
<li><span>{lang('LoginQRHelp1')}</span></li>
|
||||
<li><span>{lang('LoginQRHelp2', undefined, { withNodes: true, withMarkdown: true })}</span></li>
|
||||
<li><span>{lang('LoginQRHelp3')}</span></li>
|
||||
</ol>
|
||||
{isAuthReady && (
|
||||
<Button isText onClick={habdleReturnToAuthPhoneNumber}>{lang('Login.QR.Cancel')}</Button>
|
||||
<Button isText onClick={habdleReturnToAuthPhoneNumber}>{lang('LoginQRCancel')}</Button>
|
||||
)}
|
||||
{suggestedLanguage && suggestedLanguage !== language && continueText && (
|
||||
<Button isText isLoading={isLoading} onClick={handleLangChange}>{continueText}</Button>
|
||||
|
||||
@ -7,35 +7,35 @@ import type { GlobalState } from '../../global/types';
|
||||
|
||||
import { pick } from '../../util/iteratees';
|
||||
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import useLang from '../../hooks/useLang';
|
||||
|
||||
import AvatarEditable from '../ui/AvatarEditable';
|
||||
import Button from '../ui/Button';
|
||||
import InputText from '../ui/InputText';
|
||||
|
||||
type StateProps = Pick<GlobalState, 'authIsLoading' | 'authError'>;
|
||||
type StateProps = Pick<GlobalState, 'authIsLoading' | 'authErrorKey'>;
|
||||
|
||||
const AuthRegister: FC<StateProps> = ({
|
||||
authIsLoading, authError,
|
||||
authIsLoading, authErrorKey,
|
||||
}) => {
|
||||
const { signUp, clearAuthError, uploadProfilePhoto } = getActions();
|
||||
const { signUp, clearAuthErrorKey, uploadProfilePhoto } = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
const [isButtonShown, setIsButtonShown] = useState(false);
|
||||
const [croppedFile, setCroppedFile] = useState<File | undefined>();
|
||||
const [firstName, setFirstName] = useState('');
|
||||
const [lastName, setLastName] = useState('');
|
||||
|
||||
const handleFirstNameChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||
if (authError) {
|
||||
clearAuthError();
|
||||
if (authErrorKey) {
|
||||
clearAuthErrorKey();
|
||||
}
|
||||
|
||||
const { target } = event;
|
||||
|
||||
setFirstName(target.value);
|
||||
setIsButtonShown(target.value.length > 0);
|
||||
}, [authError, clearAuthError]);
|
||||
}, [authErrorKey]);
|
||||
|
||||
const handleLastNameChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||
const { target } = event;
|
||||
@ -59,18 +59,18 @@ const AuthRegister: FC<StateProps> = ({
|
||||
<form action="" method="post" onSubmit={handleSubmit}>
|
||||
<AvatarEditable onChange={setCroppedFile} />
|
||||
<h2>{lang('YourName')}</h2>
|
||||
<p className="note">{lang('Login.Register.Desc')}</p>
|
||||
<p className="note">{lang('LoginRegisterDesc')}</p>
|
||||
<InputText
|
||||
id="registration-first-name"
|
||||
label={lang('Login.Register.FirstName.Placeholder')}
|
||||
label={lang('LoginRegisterFirstNamePlaceholder')}
|
||||
onChange={handleFirstNameChange}
|
||||
value={firstName}
|
||||
error={authError && lang(authError)}
|
||||
error={authErrorKey && lang.withRegular(authErrorKey)}
|
||||
autoComplete="given-name"
|
||||
/>
|
||||
<InputText
|
||||
id="registration-last-name"
|
||||
label={lang('Login.Register.LastName.Placeholder')}
|
||||
label={lang('LoginRegisterLastNamePlaceholder')}
|
||||
onChange={handleLastNameChange}
|
||||
value={lastName}
|
||||
autoComplete="family-name"
|
||||
@ -85,5 +85,5 @@ const AuthRegister: FC<StateProps> = ({
|
||||
};
|
||||
|
||||
export default memo(withGlobal(
|
||||
(global): StateProps => pick(global, ['authIsLoading', 'authError']),
|
||||
(global): StateProps => pick(global, ['authIsLoading', 'authErrorKey']),
|
||||
)(AuthRegister));
|
||||
|
||||
@ -12,7 +12,7 @@ import { isoToEmoji } from '../../util/emoji/emoji';
|
||||
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useSyncEffect from '../../hooks/useSyncEffect';
|
||||
|
||||
import DropdownMenu from '../ui/DropdownMenu';
|
||||
@ -42,7 +42,7 @@ const CountryCodeInput: FC<OwnProps & StateProps> = ({
|
||||
onChange,
|
||||
phoneCodeList,
|
||||
}) => {
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@ -120,7 +120,7 @@ const CountryCodeInput: FC<OwnProps & StateProps> = ({
|
||||
onInput={handleCodeInput}
|
||||
onKeyDown={handleInputKeyDown}
|
||||
/>
|
||||
<label>{lang('Login.SelectCountry.Title')}</label>
|
||||
<label>{lang('LoginSelectCountryTitle')}</label>
|
||||
{isLoading ? (
|
||||
<Spinner color="black" />
|
||||
) : (
|
||||
@ -154,7 +154,7 @@ const CountryCodeInput: FC<OwnProps & StateProps> = ({
|
||||
className="no-results"
|
||||
disabled
|
||||
>
|
||||
<span>{lang('lng_country_none')}</span>
|
||||
<span>{lang('CountryNone')}</span>
|
||||
</MenuItem>
|
||||
)}
|
||||
</DropdownMenu>
|
||||
|
||||
@ -8,7 +8,7 @@ import { AUTODOWNLOAD_FILESIZE_MB_LIMITS } from '../../../config';
|
||||
import { pick } from '../../../util/iteratees';
|
||||
|
||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
|
||||
import Checkbox from '../../ui/Checkbox';
|
||||
import RangeSlider from '../../ui/RangeSlider';
|
||||
@ -53,7 +53,7 @@ const SettingsDataStorage: FC<OwnProps & StateProps> = ({
|
||||
}) => {
|
||||
const { setSettingOption } = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
useHistoryBack({
|
||||
isActive,
|
||||
@ -61,7 +61,9 @@ const SettingsDataStorage: FC<OwnProps & StateProps> = ({
|
||||
});
|
||||
|
||||
const renderFileSizeCallback = useCallback((value: number) => {
|
||||
return lang('AutodownloadSizeLimitUpTo', lang('FileSize.MB', String(AUTODOWNLOAD_FILESIZE_MB_LIMITS[value]), 'i'));
|
||||
return lang('AutodownloadSizeLimitUpTo', {
|
||||
limit: lang('FileSizeMB', { count: AUTODOWNLOAD_FILESIZE_MB_LIMITS[value] }),
|
||||
});
|
||||
}, [lang]);
|
||||
|
||||
const handleFileSizeChange = useCallback((value: number) => {
|
||||
@ -98,26 +100,26 @@ const SettingsDataStorage: FC<OwnProps & StateProps> = ({
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>{title}</h4>
|
||||
|
||||
<Checkbox
|
||||
label={lang('AutoDownloadSettings.Contacts')}
|
||||
label={lang('AutoDownloadSettingsContacts')}
|
||||
checked={canAutoLoadFromContacts}
|
||||
// TODO rewrite to support `useCallback`
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onCheck={(isChecked) => setSettingOption({ [`canAutoLoad${key}FromContacts`]: isChecked })}
|
||||
/>
|
||||
<Checkbox
|
||||
label={lang('AutoDownloadSettings.PrivateChats')}
|
||||
label={lang('AutoDownloadSettingsPrivateChats')}
|
||||
checked={canAutoLoadInPrivateChats}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onCheck={(isChecked) => setSettingOption({ [`canAutoLoad${key}InPrivateChats`]: isChecked })}
|
||||
/>
|
||||
<Checkbox
|
||||
label={lang('AutoDownloadSettings.GroupChats')}
|
||||
label={lang('AutoDownloadSettingsGroupChats')}
|
||||
checked={canAutoLoadInGroups}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onCheck={(isChecked) => setSettingOption({ [`canAutoLoad${key}InGroups`]: isChecked })}
|
||||
/>
|
||||
<Checkbox
|
||||
label={lang('AutoDownloadSettings.Channels')}
|
||||
label={lang('AutoDownloadSettingsChannels')}
|
||||
checked={canAutoLoadInChannels}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onCheck={(isChecked) => setSettingOption({ [`canAutoLoad${key}InChannels`]: isChecked })}
|
||||
@ -147,7 +149,7 @@ const SettingsDataStorage: FC<OwnProps & StateProps> = ({
|
||||
canAutoLoadVideoInChannels,
|
||||
)}
|
||||
{renderAutoDownloadBlock(
|
||||
'Auto-download files', // Proper translation is not available yet
|
||||
lang('AutoDownloadFilesTitle'),
|
||||
'File',
|
||||
canAutoLoadFileFromContacts,
|
||||
canAutoLoadFileInPrivateChats,
|
||||
|
||||
@ -17,7 +17,7 @@ import {
|
||||
|
||||
import useAppLayout from '../../../hooks/useAppLayout';
|
||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
|
||||
import Checkbox from '../../ui/Checkbox';
|
||||
import ListItem from '../../ui/ListItem';
|
||||
@ -41,14 +41,6 @@ type StateProps =
|
||||
shouldUseSystemTheme: boolean;
|
||||
};
|
||||
|
||||
const TIME_FORMAT_OPTIONS: IRadioOption[] = [{
|
||||
label: '12-hour',
|
||||
value: '12h',
|
||||
}, {
|
||||
label: '24-hour',
|
||||
value: '24h',
|
||||
}];
|
||||
|
||||
const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
||||
isActive,
|
||||
onScreenSelect,
|
||||
@ -63,28 +55,36 @@ const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
||||
setSettingOption,
|
||||
} = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
const { isMobile } = useAppLayout();
|
||||
const isMobileDevice = isMobile && (IS_IOS || IS_ANDROID);
|
||||
|
||||
const timeFormatOptions: IRadioOption[] = [{
|
||||
label: lang('SettingsTimeFormat12'),
|
||||
value: '12h',
|
||||
}, {
|
||||
label: lang('SettingsTimeFormat24'),
|
||||
value: '24h',
|
||||
}];
|
||||
|
||||
const appearanceThemeOptions: IRadioOption[] = [{
|
||||
label: lang('EmptyChat.Appearance.Light'),
|
||||
label: lang('EmptyChatAppearanceLight'),
|
||||
value: 'light',
|
||||
}, {
|
||||
label: lang('EmptyChat.Appearance.Dark'),
|
||||
label: lang('EmptyChatAppearanceDark'),
|
||||
value: 'dark',
|
||||
}, {
|
||||
label: lang('EmptyChat.Appearance.System'),
|
||||
label: lang('EmptyChatAppearanceSystem'),
|
||||
value: 'auto',
|
||||
}];
|
||||
|
||||
const keyboardSendOptions = !isMobileDevice ? [
|
||||
{ value: 'enter', label: lang('lng_settings_send_enter'), subLabel: 'New line by Shift + Enter' },
|
||||
{ value: 'enter', label: lang('SettingsSendEnter'), subLabel: lang('SettingsSendEnterDescription') },
|
||||
{
|
||||
value: 'ctrl-enter',
|
||||
label: lang(IS_MAC_OS || IS_IOS ? 'lng_settings_send_cmdenter' : 'lng_settings_send_ctrlenter'),
|
||||
subLabel: 'New line by Enter',
|
||||
label: lang(IS_MAC_OS || IS_IOS ? 'SettingsSendCmdenter' : 'SettingsSendCtrlenter'),
|
||||
subLabel: lang('SettingsSendPlusEnterDescription'),
|
||||
},
|
||||
] : undefined;
|
||||
|
||||
@ -134,7 +134,7 @@ const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<div className="settings-content custom-scroll">
|
||||
<div className="settings-item pt-3">
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>{lang('SETTINGS')}</h4>
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>{lang('Settings')}</h4>
|
||||
|
||||
<RangeSlider
|
||||
label={lang('TextSize')}
|
||||
@ -155,7 +155,7 @@ const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
||||
|
||||
{IS_ELECTRON && IS_WINDOWS && (
|
||||
<Checkbox
|
||||
label={lang('GeneralSettings.StatusBarItem')}
|
||||
label={lang('SettingsTray')}
|
||||
checked={Boolean(isTrayIconEnabled)}
|
||||
onCheck={handleIsTrayIconEnabledChange}
|
||||
/>
|
||||
@ -176,11 +176,11 @@ const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
||||
|
||||
<div className="settings-item">
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
Time Format
|
||||
{lang('SettingsTimeFormat')}
|
||||
</h4>
|
||||
<RadioGroup
|
||||
name="timeformat"
|
||||
options={TIME_FORMAT_OPTIONS}
|
||||
options={timeFormatOptions}
|
||||
selected={timeFormat}
|
||||
onChange={handleTimeFormatChange}
|
||||
/>
|
||||
@ -188,7 +188,7 @@ const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
||||
|
||||
{keyboardSendOptions && (
|
||||
<div className="settings-item">
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>{lang('VoiceOver.Keyboard')}</h4>
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>{lang('SettingsKeyboard')}</h4>
|
||||
|
||||
<RadioGroup
|
||||
name="keyboard-send-settings"
|
||||
|
||||
@ -163,7 +163,7 @@ const SettingsHeader: FC<OwnProps> = ({
|
||||
return <h3>{oldLang('NeverAllow')}</h3>;
|
||||
|
||||
case SettingsScreens.Performance:
|
||||
return <h3>{oldLang('Animations and Performance')}</h3>;
|
||||
return <h3>{lang('MenuAnimations')}</h3>;
|
||||
|
||||
case SettingsScreens.ActiveSessions:
|
||||
return <h3>{oldLang('SessionsTitle')}</h3>;
|
||||
|
||||
@ -16,7 +16,6 @@ import useFlag from '../../../hooks/useFlag';
|
||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
|
||||
import StarIcon from '../../common/icons/StarIcon';
|
||||
import ChatExtra from '../../common/profile/ChatExtra';
|
||||
@ -62,7 +61,6 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
const [isSupportDialogOpen, openSupportDialog, closeSupportDialog] = useFlag(false);
|
||||
|
||||
const lang = useLang();
|
||||
const oldLang = useOldLang();
|
||||
|
||||
useEffect(() => {
|
||||
if (currentUserId) {
|
||||
@ -104,7 +102,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onScreenSelect(SettingsScreens.General)}
|
||||
>
|
||||
{oldLang('Telegram.GeneralSettingsViewController')}
|
||||
{lang('TelegramGeneralSettingsViewController')}
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon="animations"
|
||||
@ -112,7 +110,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onScreenSelect(SettingsScreens.Performance)}
|
||||
>
|
||||
{oldLang('Animations and Performance')}
|
||||
{lang('MenuAnimations')}
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon="unmute"
|
||||
@ -120,7 +118,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onScreenSelect(SettingsScreens.Notifications)}
|
||||
>
|
||||
{oldLang('Notifications')}
|
||||
{lang('Notifications')}
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon="data"
|
||||
@ -128,7 +126,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onScreenSelect(SettingsScreens.DataStorage)}
|
||||
>
|
||||
{oldLang('DataSettings')}
|
||||
{lang('DataSettings')}
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon="lock"
|
||||
@ -136,7 +134,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onScreenSelect(SettingsScreens.Privacy)}
|
||||
>
|
||||
{oldLang('PrivacySettings')}
|
||||
{lang('PrivacySettings')}
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon="folder"
|
||||
@ -144,7 +142,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onScreenSelect(SettingsScreens.Folders)}
|
||||
>
|
||||
{oldLang('Filters')}
|
||||
{lang('Filters')}
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon="active-sessions"
|
||||
@ -152,7 +150,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onScreenSelect(SettingsScreens.ActiveSessions)}
|
||||
>
|
||||
{oldLang('SessionsTitle')}
|
||||
{lang('SessionsTitle')}
|
||||
{sessionCount > 0 && (<span className="settings-item__current-value">{sessionCount}</span>)}
|
||||
</ListItem>
|
||||
<ListItem
|
||||
@ -161,8 +159,8 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onScreenSelect(SettingsScreens.Language)}
|
||||
>
|
||||
{oldLang('Language')}
|
||||
<span className="settings-item__current-value">{oldLang.langName}</span>
|
||||
{lang('Language')}
|
||||
<span className="settings-item__current-value">{lang.languageInfo.nativeName}</span>
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon="stickers"
|
||||
@ -170,7 +168,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onScreenSelect(SettingsScreens.Stickers)}
|
||||
>
|
||||
{oldLang('StickersName')}
|
||||
{lang('MenuStickers')}
|
||||
</ListItem>
|
||||
</div>
|
||||
<div className="settings-main-menu">
|
||||
@ -181,7 +179,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => openPremiumModal()}
|
||||
>
|
||||
{oldLang('TelegramPremium')}
|
||||
{lang('TelegramPremium')}
|
||||
</ListItem>
|
||||
)}
|
||||
{shouldDisplayStars && (
|
||||
@ -191,7 +189,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => openStarsBalanceModal({})}
|
||||
>
|
||||
{oldLang('MenuTelegramStars')}
|
||||
{lang('MenuStars')}
|
||||
{Boolean(starsBalance) && (
|
||||
<span className="settings-item__current-value">
|
||||
{formatStarsAmount(lang, starsBalance)}
|
||||
@ -206,7 +204,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => openGiftRecipientPicker()}
|
||||
>
|
||||
{oldLang('SendAGift')}
|
||||
{lang('MenuSendGift')}
|
||||
</ListItem>
|
||||
)}
|
||||
</div>
|
||||
@ -216,7 +214,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
narrow
|
||||
onClick={openSupportDialog}
|
||||
>
|
||||
{oldLang('AskAQuestion')}
|
||||
{lang('AskAQuestion')}
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon="help"
|
||||
@ -224,7 +222,7 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => openUrl({ url: FAQ_URL })}
|
||||
>
|
||||
{oldLang('TelegramFaq')}
|
||||
{lang('MenuTelegramFaq')}
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon="privacy-policy"
|
||||
@ -232,14 +230,14 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => openUrl({ url: PRIVACY_URL })}
|
||||
>
|
||||
{oldLang('PrivacyPolicy')}
|
||||
{lang('MenuPrivacyPolicy')}
|
||||
</ListItem>
|
||||
</div>
|
||||
<ConfirmDialog
|
||||
isOpen={isSupportDialogOpen}
|
||||
confirmLabel={oldLang('lng_settings_ask_ok')}
|
||||
title={oldLang('AskAQuestion')}
|
||||
text={oldLang('lng_settings_ask_sure')}
|
||||
confirmLabel={lang('OK')}
|
||||
title={lang('AskAQuestion')}
|
||||
textParts={lang('MenuAskText', undefined, { withNodes: true, renderTextFilters: ['br'] })}
|
||||
confirmHandler={handleOpenSupport}
|
||||
onClose={closeSupportDialog}
|
||||
/>
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
} from '../../../util/notifications';
|
||||
|
||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useRunDebounced from '../../../hooks/useRunDebounced';
|
||||
|
||||
import Checkbox from '../../ui/Checkbox';
|
||||
@ -139,7 +139,7 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
||||
runDebounced(() => playNotifySound(undefined, volume));
|
||||
}, [runDebounced, updateWebNotificationSettings]);
|
||||
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
useHistoryBack({
|
||||
isActive,
|
||||
@ -150,27 +150,27 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
||||
<div className="settings-content custom-scroll">
|
||||
<div className="settings-item">
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
Web notifications
|
||||
{lang('NotificationsWeb')}
|
||||
</h4>
|
||||
<Checkbox
|
||||
label="Web notifications"
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={lang(hasWebNotifications ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
label={lang('NotificationsWeb')}
|
||||
subLabel={lang(hasWebNotifications ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||
checked={hasWebNotifications}
|
||||
disabled={!areNotificationsSupported}
|
||||
onChange={handleWebNotificationsChange}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Offline notifications"
|
||||
label={lang('NotificationsOffline')}
|
||||
disabled={!hasWebNotifications || !areOfflineNotificationsSupported}
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={areOfflineNotificationsSupported ? lang(hasPushNotifications ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled') : 'Not supported'}
|
||||
subLabel={areOfflineNotificationsSupported
|
||||
? lang(hasPushNotifications ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')
|
||||
: lang('SettingsOfflineNotificationUnsupported')}
|
||||
checked={hasPushNotifications}
|
||||
onChange={handlePushNotificationsChange}
|
||||
/>
|
||||
<div className="settings-item-slider">
|
||||
<RangeSlider
|
||||
label="Sound"
|
||||
label={lang('NotificationsSound')}
|
||||
min={0}
|
||||
max={10}
|
||||
disabled={!areNotificationsSupported}
|
||||
@ -186,16 +186,16 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
||||
|
||||
<Checkbox
|
||||
label={lang('NotificationsForPrivateChats')}
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={lang(hasPrivateChatsNotifications ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
subLabel={lang(hasPrivateChatsNotifications
|
||||
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||
checked={hasPrivateChatsNotifications}
|
||||
onChange={handlePrivateChatsNotificationsChange}
|
||||
/>
|
||||
<Checkbox
|
||||
label={lang('MessagePreview')}
|
||||
disabled={!hasPrivateChatsNotifications}
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={lang(hasPrivateChatsMessagePreview ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
subLabel={lang(hasPrivateChatsMessagePreview
|
||||
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||
checked={hasPrivateChatsMessagePreview}
|
||||
onChange={handlePrivateChatsPreviewChange}
|
||||
/>
|
||||
@ -206,14 +206,14 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
||||
|
||||
<Checkbox
|
||||
label={lang('NotificationsForGroups')}
|
||||
subLabel={lang(hasGroupNotifications ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
subLabel={lang(hasGroupNotifications ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||
checked={hasGroupNotifications}
|
||||
onChange={handleGroupsNotificationsChange}
|
||||
/>
|
||||
<Checkbox
|
||||
label={lang('MessagePreview')}
|
||||
disabled={!hasGroupNotifications}
|
||||
subLabel={lang(hasGroupMessagePreview ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
subLabel={lang(hasGroupMessagePreview ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||
checked={hasGroupMessagePreview}
|
||||
onChange={handleGroupsPreviewChange}
|
||||
/>
|
||||
@ -224,16 +224,14 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
||||
|
||||
<Checkbox
|
||||
label={lang('NotificationsForChannels')}
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={lang(hasBroadcastNotifications ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
subLabel={lang(hasBroadcastNotifications ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||
checked={hasBroadcastNotifications}
|
||||
onChange={handleChannelsNotificationsChange}
|
||||
/>
|
||||
<Checkbox
|
||||
label={lang('MessagePreview')}
|
||||
disabled={!hasBroadcastNotifications}
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={lang(hasBroadcastMessagePreview ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
subLabel={lang(hasBroadcastMessagePreview ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||
checked={hasBroadcastMessagePreview}
|
||||
onChange={handleChannelsPreviewChange}
|
||||
/>
|
||||
|
||||
@ -4,6 +4,7 @@ import React, {
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { AnimationLevel, PerformanceType, PerformanceTypeKey } from '../../../types';
|
||||
import type { RegularLangKey } from '../../../types/language';
|
||||
|
||||
import {
|
||||
ANIMATION_LEVEL_CUSTOM, ANIMATION_LEVEL_MAX, ANIMATION_LEVEL_MED, ANIMATION_LEVEL_MIN,
|
||||
@ -18,15 +19,15 @@ import { areDeepEqual } from '../../../util/areDeepEqual';
|
||||
import { IS_BACKDROP_BLUR_SUPPORTED, IS_SNAP_EFFECT_SUPPORTED } from '../../../util/windowEnvironment';
|
||||
|
||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
|
||||
import Checkbox from '../../ui/Checkbox';
|
||||
import RangeSlider from '../../ui/RangeSlider';
|
||||
|
||||
type PerformanceSection = [string, PerformanceOption[]];
|
||||
type PerformanceSection = [RegularLangKey, PerformanceOption[]];
|
||||
type PerformanceOption = {
|
||||
key: PerformanceTypeKey;
|
||||
label: string;
|
||||
label: RegularLangKey;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
@ -39,38 +40,38 @@ type StateProps = {
|
||||
performanceSettings: PerformanceType;
|
||||
};
|
||||
|
||||
const ANIMATION_LEVEL_OPTIONS = [
|
||||
'Power Saving',
|
||||
'Nice and Fast',
|
||||
'Lots of Stuff',
|
||||
const ANIMATION_LEVEL_OPTIONS: RegularLangKey[] = [
|
||||
'SettingsPerformanceSliderLow',
|
||||
'SettingsPerformanceSliderMedium',
|
||||
'SettingsPerformanceSliderHigh',
|
||||
];
|
||||
|
||||
const ANIMATION_LEVEL_CUSTOM_OPTIONS = [
|
||||
'Power Saving',
|
||||
'Custom',
|
||||
'Lots of Stuff',
|
||||
const ANIMATION_LEVEL_CUSTOM_OPTIONS: RegularLangKey[] = [
|
||||
'SettingsPerformanceSliderLow',
|
||||
'SettingsPerformanceSliderCustom',
|
||||
'SettingsPerformanceSliderHigh',
|
||||
];
|
||||
|
||||
const PERFORMANCE_OPTIONS: PerformanceSection[] = [
|
||||
['LiteMode.Key.animations.Title', [
|
||||
{ key: 'pageTransitions', label: 'Page Transitions' },
|
||||
{ key: 'messageSendingAnimations', label: 'Message Sending Animation' },
|
||||
{ key: 'mediaViewerAnimations', label: 'Media Viewer Animations' },
|
||||
{ key: 'messageComposerAnimations', label: 'Message Composer Animations' },
|
||||
{ key: 'contextMenuAnimations', label: 'Context Menu Animation' },
|
||||
{ key: 'contextMenuBlur', label: 'Context Menu Blur', disabled: !IS_BACKDROP_BLUR_SUPPORTED },
|
||||
{ key: 'rightColumnAnimations', label: 'Right Column Animation' },
|
||||
{ key: 'snapEffect', label: 'Dust-effect deletion' },
|
||||
['SettingsPerformanceInterfaceAnimations', [
|
||||
{ key: 'pageTransitions', label: 'SettingsPerformancePageTransitions' },
|
||||
{ key: 'messageSendingAnimations', label: 'SettingsPerformanceSending' },
|
||||
{ key: 'mediaViewerAnimations', label: 'SettingsPerformanceMediaViewer' },
|
||||
{ key: 'messageComposerAnimations', label: 'SettingsPerformanceComposer' },
|
||||
{ key: 'contextMenuAnimations', label: 'SettingsPerformanceContextAnimation' },
|
||||
{ key: 'contextMenuBlur', label: 'SettingsPerformanceContextBlur', disabled: !IS_BACKDROP_BLUR_SUPPORTED },
|
||||
{ key: 'rightColumnAnimations', label: 'SettingsPerformanceRightColumn' },
|
||||
{ key: 'snapEffect', label: 'SettingsPerformanceThanos' },
|
||||
]],
|
||||
['Stickers and Emoji', [
|
||||
{ key: 'animatedEmoji', label: 'Allow Animated Emoji' },
|
||||
{ key: 'loopAnimatedStickers', label: 'Loop Animated Stickers' },
|
||||
{ key: 'reactionEffects', label: 'Reaction Effects' },
|
||||
{ key: 'stickerEffects', label: 'Full-Screen Sticker and Emoji Effects' },
|
||||
['SettingsPerformanceStickers', [
|
||||
{ key: 'animatedEmoji', label: 'SettingsPerformanceAnimatedEmoji' },
|
||||
{ key: 'loopAnimatedStickers', label: 'SettingsPerformanceLoopStickers' },
|
||||
{ key: 'reactionEffects', label: 'SettingsPerformanceReactionEffects' },
|
||||
{ key: 'stickerEffects', label: 'SettingsPerformanceStickerEffects' },
|
||||
]],
|
||||
['AutoplayMedia', [
|
||||
{ key: 'autoplayGifs', label: 'AutoplayGIF' },
|
||||
{ key: 'autoplayVideos', label: 'AutoplayVideo' },
|
||||
['SettingsPerformanceMediaAutoplay', [
|
||||
{ key: 'autoplayGifs', label: 'SettingsPerformanceAutoplayGif' },
|
||||
{ key: 'autoplayVideos', label: 'SettingsPerformanceAutoplayVideo' },
|
||||
]],
|
||||
];
|
||||
|
||||
@ -89,7 +90,7 @@ function SettingsPerformance({
|
||||
onBack: onReset,
|
||||
});
|
||||
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
const [sectionExpandedStates, setSectionExpandedStates] = useState<Record<number, boolean>>({});
|
||||
|
||||
const sectionCheckedStates = useMemo(() => {
|
||||
@ -113,9 +114,14 @@ function SettingsPerformance({
|
||||
|
||||
return ANIMATION_LEVEL_CUSTOM;
|
||||
}, [performanceSettings]);
|
||||
const animationLevelOptions = animationLevelState === ANIMATION_LEVEL_CUSTOM
|
||||
? ANIMATION_LEVEL_CUSTOM_OPTIONS
|
||||
: ANIMATION_LEVEL_OPTIONS;
|
||||
|
||||
const animationLevelOptions = useMemo(() => {
|
||||
const options = animationLevelState === ANIMATION_LEVEL_CUSTOM
|
||||
? ANIMATION_LEVEL_CUSTOM_OPTIONS
|
||||
: ANIMATION_LEVEL_OPTIONS;
|
||||
|
||||
return options.map((option) => lang(option));
|
||||
}, [animationLevelState, lang]);
|
||||
|
||||
const handleToggleSection = useCallback((e: React.MouseEvent, index?: string) => {
|
||||
e.preventDefault();
|
||||
@ -161,10 +167,10 @@ function SettingsPerformance({
|
||||
<div className="settings-content custom-scroll">
|
||||
<div className="settings-item">
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
Animation Level
|
||||
{lang('SettingsPerformanceSliderTitle')}
|
||||
</h4>
|
||||
<p className="settings-item-description" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
Choose the desired animations amount.
|
||||
{lang('SettingsPerformanceSliderSubtitle')}
|
||||
</p>
|
||||
|
||||
<RangeSlider
|
||||
|
||||
@ -323,7 +323,6 @@ export const MAX_MEDIA_FILES_FOR_ALBUM = 10;
|
||||
export const MAX_ACTIVE_PINNED_CHATS = 5;
|
||||
export const SCHEDULED_WHEN_ONLINE = 0x7FFFFFFE;
|
||||
export const DEFAULT_LANG_CODE = 'en';
|
||||
export const OLD_DEFAULT_LANG_PACK = 'android';
|
||||
export const LANG_PACKS = ['android', 'ios', 'tdesktop', 'macos'] as const;
|
||||
export const FEEDBACK_URL = 'https://bugs.telegram.org/?tag_ids=41&sort=time';
|
||||
export const FAQ_URL = 'https://telegram.org/faq';
|
||||
|
||||
@ -69,7 +69,7 @@ addActionHandler('setAuthPhoneNumber', (global, actions, payload): ActionReturnT
|
||||
return {
|
||||
...global,
|
||||
authIsLoading: true,
|
||||
authError: undefined,
|
||||
authErrorKey: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
@ -81,7 +81,7 @@ addActionHandler('setAuthCode', (global, actions, payload): ActionReturnType =>
|
||||
return {
|
||||
...global,
|
||||
authIsLoading: true,
|
||||
authError: undefined,
|
||||
authErrorKey: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
@ -93,7 +93,7 @@ addActionHandler('setAuthPassword', (global, actions, payload): ActionReturnType
|
||||
return {
|
||||
...global,
|
||||
authIsLoading: true,
|
||||
authError: undefined,
|
||||
authErrorKey: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
@ -124,7 +124,7 @@ addActionHandler('signUp', (global, actions, payload): ActionReturnType => {
|
||||
return {
|
||||
...global,
|
||||
authIsLoading: true,
|
||||
authError: undefined,
|
||||
authErrorKey: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
@ -133,7 +133,7 @@ addActionHandler('returnToAuthPhoneNumber', (global): ActionReturnType => {
|
||||
|
||||
return {
|
||||
...global,
|
||||
authError: undefined,
|
||||
authErrorKey: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
@ -143,7 +143,7 @@ addActionHandler('goToAuthQrCode', (global): ActionReturnType => {
|
||||
return {
|
||||
...global,
|
||||
authIsLoadingQrCode: true,
|
||||
authError: undefined,
|
||||
authErrorKey: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@ -180,10 +180,9 @@ function onUpdateAuthorizationState<T extends GlobalState>(global: T, update: Ap
|
||||
}
|
||||
|
||||
function onUpdateAuthorizationError<T extends GlobalState>(global: T, update: ApiUpdateAuthorizationError) {
|
||||
global = getGlobal();
|
||||
global = {
|
||||
...global,
|
||||
authError: update.message,
|
||||
authErrorKey: update.errorKey,
|
||||
};
|
||||
setGlobal(global);
|
||||
}
|
||||
|
||||
@ -217,10 +217,10 @@ addActionHandler('setAuthRememberMe', (global, actions, payload): ActionReturnTy
|
||||
};
|
||||
});
|
||||
|
||||
addActionHandler('clearAuthError', (global): ActionReturnType => {
|
||||
addActionHandler('clearAuthErrorKey', (global): ActionReturnType => {
|
||||
return {
|
||||
...global,
|
||||
authError: undefined,
|
||||
authErrorKey: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@ -116,7 +116,7 @@ export interface ActionPayloads {
|
||||
};
|
||||
returnToAuthPhoneNumber: undefined;
|
||||
setAuthRememberMe: boolean;
|
||||
clearAuthError: undefined;
|
||||
clearAuthErrorKey: undefined;
|
||||
uploadProfilePhoto: {
|
||||
file: File;
|
||||
isFallback?: boolean;
|
||||
|
||||
@ -68,6 +68,7 @@ import type {
|
||||
TopicsInfo,
|
||||
WebPageMediaSize,
|
||||
} from '../../types';
|
||||
import type { RegularLangFnParameters } from '../../util/localization';
|
||||
import type { TabState } from './tabState';
|
||||
|
||||
export type GlobalState = {
|
||||
@ -145,7 +146,7 @@ export type GlobalState = {
|
||||
authPhoneNumber?: string;
|
||||
authIsLoading?: boolean;
|
||||
authIsLoadingQrCode?: boolean;
|
||||
authError?: string;
|
||||
authErrorKey?: RegularLangFnParameters;
|
||||
authRememberMe?: boolean;
|
||||
authNearestCountry?: string;
|
||||
authIsCodeViaApp?: boolean;
|
||||
|
||||
30
src/hooks/useLangString.ts
Normal file
30
src/hooks/useLangString.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { useEffect, useState } from '../lib/teact/teact';
|
||||
|
||||
import type { RegularLangKey } from '../types/language';
|
||||
|
||||
import { LANG_PACK } from '../config';
|
||||
import { callApi } from '../api/gramjs';
|
||||
import useLastCallback from './useLastCallback';
|
||||
|
||||
export default function useLangString(key: RegularLangKey, langCode?: string) {
|
||||
const [value, setValue] = useState<string | undefined>(undefined);
|
||||
|
||||
const fetchLangString = useLastCallback(async () => {
|
||||
if (!langCode) return undefined;
|
||||
|
||||
const result = await callApi('fetchLangStrings', {
|
||||
langCode,
|
||||
langPack: LANG_PACK,
|
||||
keys: [key],
|
||||
});
|
||||
const langString = result?.strings[0];
|
||||
if (!langString || typeof langString !== 'string') return undefined;
|
||||
return langString;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchLangString().then(setValue);
|
||||
}, [key, langCode]);
|
||||
|
||||
return value;
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
import * as langProvider from '../util/oldLangProvider';
|
||||
import useAsync from './useAsync';
|
||||
|
||||
/**
|
||||
* @deprecated Migrate to `useLang`, while using needed key inside initial fallback
|
||||
*/
|
||||
const useOldLangString = (
|
||||
langCode: string | undefined,
|
||||
key: string,
|
||||
shouldIgnoreSameValue = false,
|
||||
): string | undefined => {
|
||||
const defaultValue = shouldIgnoreSameValue ? undefined : key;
|
||||
const { result } = useAsync(() => {
|
||||
if (langCode) {
|
||||
return langProvider.getTranslationForLangString(langCode, key);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}, [langCode, key], defaultValue);
|
||||
|
||||
return result || defaultValue;
|
||||
};
|
||||
|
||||
export default useOldLangString;
|
||||
58
src/types/language.d.ts
vendored
58
src/types/language.d.ts
vendored
@ -142,7 +142,7 @@ export interface LangPair {
|
||||
'LoginQRLogin': undefined;
|
||||
'LoginQRTitle': undefined;
|
||||
'LoginQRHelp1': undefined;
|
||||
'LoginQR2Help2': undefined;
|
||||
'LoginQRHelp2': undefined;
|
||||
'LoginQRHelp3': undefined;
|
||||
'LoginQRCancel': undefined;
|
||||
'YourName': undefined;
|
||||
@ -344,6 +344,8 @@ export interface LangPair {
|
||||
'AuthSessionsViewBrowser': undefined;
|
||||
'AuthSessionsViewLocationInfo': undefined;
|
||||
'AuthSessionsLogOutApplications': undefined;
|
||||
'AuthKeepSignedIn': undefined;
|
||||
'AuthTitle': undefined;
|
||||
'ClearOtherWebSessionsHelp': undefined;
|
||||
'AreYouSureWebSessions': undefined;
|
||||
'AutoDownloadMaxFileSize': undefined;
|
||||
@ -369,10 +371,17 @@ export interface LangPair {
|
||||
'SettingsSendEnter': undefined;
|
||||
'SettingsSendCmdenter': undefined;
|
||||
'SettingsSendCtrlenter': undefined;
|
||||
'SettingsSendEnterDescription': undefined;
|
||||
'SettingsSendPlusEnterDescription': undefined;
|
||||
'SettingsTimeFormat': undefined;
|
||||
'SettingsTimeFormat12': undefined;
|
||||
'SettingsTimeFormat24': undefined;
|
||||
'SettingsKeyboard': undefined;
|
||||
'SettingsTray': undefined;
|
||||
'SettingsOfflineNotificationUnsupported': undefined;
|
||||
'TextSize': undefined;
|
||||
'ChatBackground': undefined;
|
||||
'Theme': undefined;
|
||||
'VoiceOverKeyboard': undefined;
|
||||
'AccDescrStickers': undefined;
|
||||
'DoubleTapSetting': undefined;
|
||||
'SuggestStickers': undefined;
|
||||
@ -544,10 +553,46 @@ export interface LangPair {
|
||||
'PollsSolutionTitle': undefined;
|
||||
'CreatePollExplanationInfo': undefined;
|
||||
'VoipGroupPersonalAccount': undefined;
|
||||
'MenuStickers': undefined;
|
||||
'MenuAnimations': undefined;
|
||||
'MenuStars': undefined;
|
||||
'MenuSendGift': undefined;
|
||||
'MenuTelegramFaq': undefined;
|
||||
'MenuPrivacyPolicy': undefined;
|
||||
'MenuAskText': undefined;
|
||||
'SettingsPerformanceSliderTitle': undefined;
|
||||
'SettingsPerformanceSliderSubtitle': undefined;
|
||||
'SettingsPerformanceSliderLow': undefined;
|
||||
'SettingsPerformanceSliderMedium': undefined;
|
||||
'SettingsPerformanceSliderCustom': undefined;
|
||||
'SettingsPerformanceSliderHigh': undefined;
|
||||
'SettingsPerformanceInterfaceAnimations': undefined;
|
||||
'SettingsPerformanceStickers': undefined;
|
||||
'SettingsPerformanceMediaAutoplay': undefined;
|
||||
'SettingsPerformancePageTransitions': undefined;
|
||||
'SettingsPerformanceSending': undefined;
|
||||
'SettingsPerformanceMediaViewer': undefined;
|
||||
'SettingsPerformanceComposer': undefined;
|
||||
'SettingsPerformanceContextAnimation': undefined;
|
||||
'SettingsPerformanceContextBlur': undefined;
|
||||
'SettingsPerformanceRightColumn': undefined;
|
||||
'SettingsPerformanceThanos': undefined;
|
||||
'SettingsPerformanceAnimatedEmoji': undefined;
|
||||
'SettingsPerformanceLoopStickers': undefined;
|
||||
'SettingsPerformanceReactionEffects': undefined;
|
||||
'SettingsPerformanceStickerEffects': undefined;
|
||||
'SettingsPerformanceAutoplayGif': undefined;
|
||||
'SettingsPerformanceAutoplayVideo': undefined;
|
||||
'FavoriteStickers': undefined;
|
||||
'PremiumStickers': undefined;
|
||||
'GroupStickers': undefined;
|
||||
'ErrorSendRestrictedStickersAll': undefined;
|
||||
'ErrorPhoneNumberInvalid': undefined;
|
||||
'ErrorCodeInvalid': undefined;
|
||||
'ErrorIncorrectPassword': undefined;
|
||||
'ErrorPasswordFlood': undefined;
|
||||
'ErrorPhoneBanned': undefined;
|
||||
'ErrorUnexpected': undefined;
|
||||
'NoStickers': undefined;
|
||||
'ClearRecentEmoji': undefined;
|
||||
'TextFormatAddLinkTitle': undefined;
|
||||
@ -994,7 +1039,6 @@ export interface LangPair {
|
||||
'SettingsAnimationsHigh': undefined;
|
||||
'Settings12HourFormat': undefined;
|
||||
'Settings24HourFormat': undefined;
|
||||
'SettingsSendEnterDescription': undefined;
|
||||
'SettingsSendCtrlEnterDescription': undefined;
|
||||
'AriaMoreButton': undefined;
|
||||
'RecoveryEmailCode': undefined;
|
||||
@ -1094,7 +1138,6 @@ export interface LangPair {
|
||||
'HideCaption': undefined;
|
||||
'ChangeRecipient': undefined;
|
||||
'DragToSortAria': undefined;
|
||||
'SettingsTimeFormat': undefined;
|
||||
'MenuReportBug': undefined;
|
||||
'MenuBetaChangelog': undefined;
|
||||
'MenuSwitchToK': undefined;
|
||||
@ -1239,6 +1282,7 @@ export interface LangPair {
|
||||
'ViewButtonBoost': undefined;
|
||||
'ViewButtonStickerset': undefined;
|
||||
'ViewButtonGiftUnique': undefined;
|
||||
'AuthContinueOnThisLanguage': undefined;
|
||||
}
|
||||
|
||||
export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
||||
@ -1404,6 +1448,9 @@ export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
||||
'SlowModeHint': {
|
||||
'time': V;
|
||||
};
|
||||
'ErrorUnexpectedMessage': {
|
||||
'error': V;
|
||||
};
|
||||
'EditedDate': {
|
||||
'date': V;
|
||||
};
|
||||
@ -1761,6 +1808,9 @@ export interface LangPairPluralWithVariables<V extends unknown = LangVariable> {
|
||||
'PreviewSenderSendFile': {
|
||||
'count': V;
|
||||
};
|
||||
'ErrorFlood': {
|
||||
'hour': V;
|
||||
};
|
||||
'PinnedMessageTitle': {
|
||||
'index': V;
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { DEBUG } from '../../config';
|
||||
|
||||
export default function readStrings(data: string): Record<string, string> {
|
||||
const lines = data.split(/;?\r?\n/);
|
||||
const lines = data.split(/;\r?\n?/);
|
||||
const result: Record<string, string> = {};
|
||||
for (const line of lines) {
|
||||
if (!line.startsWith('"')) continue;
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
/* eslint-disable max-len */
|
||||
|
||||
import type { ApiOldLangPack } from '../api/types';
|
||||
|
||||
export const fallbackLangPackInitial = {
|
||||
WrongNumber: 'Wrong number?',
|
||||
SentAppCode: 'We\'ve sent the code to the **Telegram** app on your other device.',
|
||||
'Login.JustSentSms': 'We have sent you a code via SMS. Please enter it above.',
|
||||
'Login.Header.Password': 'Enter Password',
|
||||
'Login.EnterPasswordDescription': 'You have Two-Step Verification enabled, so your account is protected with an additional password.',
|
||||
StartText: 'Please confirm your country code and enter your phone number.',
|
||||
'Login.PhonePlaceholder': 'Your phone number',
|
||||
'Login.Next': 'Next',
|
||||
'Login.QR.Login': 'Log in by QR Code',
|
||||
'Login.QR.Title': 'Log in to Telegram by QR Code',
|
||||
'Login.QR.Help1': 'Open Telegram on your phone',
|
||||
'Login.QR.Help2': 'Go to **Settings** > **Devices** > **Link Desktop Device**',
|
||||
'Login.QR2.Help2': 'Go to **Settings** → **Devices** → **Link Desktop Device**',
|
||||
'Login.QR.Help3': 'Point your phone at this screen to confirm login',
|
||||
'Login.QR.Cancel': 'Log in by phone Number',
|
||||
YourName: 'Your Name',
|
||||
'Login.Register.Desc': 'Enter your name and add a profile picture.',
|
||||
'Login.Register.FirstName.Placeholder': 'First Name',
|
||||
'Login.Register.LastName.Placeholder': 'Last Name',
|
||||
'Login.SelectCountry.Title': 'Country',
|
||||
lng_country_none: 'Country not found',
|
||||
PleaseEnterPassword: 'Enter your new password',
|
||||
PHONE_NUMBER_INVALID: 'Invalid phone number',
|
||||
PHONE_CODE_INVALID: 'Invalid code',
|
||||
PASSWORD_HASH_INVALID: 'Incorrect password',
|
||||
PHONE_PASSWORD_FLOOD: 'Limit exceeded. Please try again later.',
|
||||
PHONE_NUMBER_BANNED: 'This phone number is banned.',
|
||||
} as ApiOldLangPack;
|
||||
@ -320,10 +320,17 @@ function createTranslationFn(): LangFn {
|
||||
}
|
||||
return processTranslation(key, variables as Record<string, LangVariable>, options);
|
||||
});
|
||||
fn.withRegular = (({ key, variables, options }: RegularLangFnParameters) => {
|
||||
return processTranslation(key, variables, options);
|
||||
});
|
||||
fn.withAdvanced = (({ key, variables, options }: AdvancedLangFnParameters) => {
|
||||
return processTranslationAdvanced(key, variables, options);
|
||||
});
|
||||
fn.region = (code: string) => formatters?.region.of(code);
|
||||
fn.conjunction = (list: string[]) => formatters?.conjunction.format(list) || list.join(', ');
|
||||
fn.disjunction = (list: string[]) => formatters?.disjunction.format(list) || list.join(', ');
|
||||
fn.number = (value: number) => formatters?.number.format(value) || String(value);
|
||||
fn.languageInfo = language!;
|
||||
return fn;
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { TeactNode } from '../../lib/teact/teact';
|
||||
|
||||
import type {
|
||||
ApiLanguage,
|
||||
LangPackStringValue,
|
||||
LangPackStringValueDeleted,
|
||||
LangPackStringValuePlural,
|
||||
@ -143,6 +144,8 @@ export type LangFn = {
|
||||
): TeactNode;
|
||||
|
||||
with: (params: LangFnParameters) => TeactNode;
|
||||
withRegular: (params: RegularLangFnParameters) => string;
|
||||
withAdvanced: (params: AdvancedLangFnParameters) => TeactNode;
|
||||
region: (code: string) => string | undefined;
|
||||
conjunction: (list: string[]) => string;
|
||||
disjunction: (list: string[]) => string;
|
||||
@ -150,6 +153,7 @@ export type LangFn = {
|
||||
isRtl?: boolean;
|
||||
code: string;
|
||||
pluralCode: string;
|
||||
languageInfo: ApiLanguage;
|
||||
};
|
||||
|
||||
type ListFormat = Pick<Intl.ListFormat, 'format'>;
|
||||
|
||||
@ -4,12 +4,11 @@ import type { ApiOldLangPack, ApiOldLangString } from '../api/types';
|
||||
import type { LangCode, TimeFormat } from '../types';
|
||||
|
||||
import {
|
||||
DEFAULT_LANG_CODE, LANG_CACHE_NAME, LANG_PACKS, OLD_DEFAULT_LANG_PACK,
|
||||
DEFAULT_LANG_CODE, LANG_CACHE_NAME, LANG_PACKS,
|
||||
} from '../config';
|
||||
import { callApi } from '../api/gramjs';
|
||||
import * as cacheApi from './cacheApi';
|
||||
import { createCallbackManager } from './callbacks';
|
||||
import { fallbackLangPackInitial } from './fallbackLangPackInitial';
|
||||
import { loadAndChangeLanguage } from './localization';
|
||||
import { formatInteger } from './textFormat';
|
||||
|
||||
@ -129,7 +128,7 @@ function createLangFn() {
|
||||
void importFallbackLangPack();
|
||||
}
|
||||
|
||||
const langString = langPack?.[key] || fallbackLangPack?.[key] || fallbackLangPackInitial[key];
|
||||
const langString = langPack?.[key] || fallbackLangPack?.[key];
|
||||
if (!langString) {
|
||||
return key;
|
||||
}
|
||||
@ -151,23 +150,6 @@ export function getTranslationFn(): LangFn {
|
||||
return translationFn;
|
||||
}
|
||||
|
||||
export async function getTranslationForLangString(langCode: string, key: string) {
|
||||
let translateString: ApiOldLangString | undefined;
|
||||
const cachedValue = await cacheApi.fetch(
|
||||
LANG_CACHE_NAME,
|
||||
`${OLD_DEFAULT_LANG_PACK}_${langCode}_${key}`,
|
||||
cacheApi.Type.Json,
|
||||
);
|
||||
|
||||
if (cachedValue) {
|
||||
translateString = cachedValue.value;
|
||||
} else {
|
||||
translateString = await fetchRemoteString(OLD_DEFAULT_LANG_PACK, langCode, key);
|
||||
}
|
||||
|
||||
return processTranslation(translateString, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Migrate to `changeLanguage` in `util/localization.ts` instead
|
||||
*/
|
||||
@ -246,28 +228,6 @@ async function fetchRemote(langCode: string): Promise<ApiOldLangPack | undefined
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function fetchRemoteString(
|
||||
remoteLangPack: typeof LANG_PACKS[number], langCode: string, key: string,
|
||||
): Promise<ApiOldLangString | undefined> {
|
||||
const remote = await callApi('oldFetchLangStrings', {
|
||||
langPack: remoteLangPack,
|
||||
langCode,
|
||||
keys: [key],
|
||||
});
|
||||
|
||||
if (remote?.length) {
|
||||
const wrappedString = JSON.stringify({
|
||||
value: remote[0],
|
||||
});
|
||||
|
||||
await cacheApi.save(LANG_CACHE_NAME, `${remoteLangPack}_${langCode}_${key}`, wrappedString);
|
||||
|
||||
return remote[0];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getPluralOption(amount: number) {
|
||||
const langCode = currentLangCode || DEFAULT_LANG_CODE;
|
||||
const optionIndex = PLURAL_RULES[langCode as keyof typeof PLURAL_RULES]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user