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