Tab List: Fix localization (#5393)

This commit is contained in:
zubiden 2025-01-03 22:21:46 +01:00 committed by Alexander Zinchuk
parent 291e911691
commit 06095b985f
6 changed files with 173 additions and 75 deletions

View File

@ -460,6 +460,8 @@
"PasscodeControllerChangeTitle" = "Change Passcode";
"FilterNew" = "New Folder";
"FilterEdit" = "Edit folder";
"FilterDelete" = "Delete folder";
"FilterShare" = "Share";
"AutoDeleteConfirm" = "Confirm";
"LogOutTitle" = "Log Out";
"AccDescrGoBack" = "Go back";
@ -1414,3 +1416,29 @@
"FolderLinkTitleDescription" = "Anyone with this link can add {folder} folder and {chats} selected below.";
"FolderLinkTitleDescriptionChats_one" = "the chat";
"FolderLinkTitleDescriptionChats_other" = "the {count} chats";
"SearchTabChats" = "Chats";
"SearchTabChannels" = "Channels";
"SearchTabApps" = "Apps";
"SearchTabMedia" = "Media";
"SearchTabLinks" = "Links";
"SearchTabFiles" = "Files";
"SearchTabMusic" = "Music";
"SearchTabVoice" = "Voice";
"SearchTabMessages" = "Messages";
"StarsTransactionsAll" = "All Transactions";
"StarsTransactionsIncoming" = "Incoming";
"StarsTransactionsOutgoing" = "Outgoing";
"ProfileTabSavedDialogs" = "Chats";
"ProfileTabStories" = "Posts";
"ProfileTabStoriesArchive" = "Story Archive";
"ProfileTabGifts" = "Gifts";
"ProfileTabSubscribers" = "Subscribers";
"ProfileTabMembers" = "Members";
"ProfileTabBotPreview" = "Preview";
"ProfileTabMedia" = "Media";
"ProfileTabFiles" = "Files";
"ProfileTabLinks" = "Links";
"ProfileTabMusic" = "Music";
"ProfileTabVoice" = "Voice";
"ProfileTabSharedGroups" = "Groups";
"ProfileTabSimilarChannels" = "Similar Channels";

View File

@ -24,8 +24,8 @@ import { renderTextWithEntities } from '../../common/helpers/renderTextWithEntit
import useDerivedState from '../../../hooks/useDerivedState';
import { useFolderManagerForUnreadCounters } from '../../../hooks/useFolderManager';
import useHistoryBack from '../../../hooks/useHistoryBack';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import useOldLang from '../../../hooks/useOldLang';
import useShowTransition from '../../../hooks/useShowTransition';
import StoryRibbon from '../../story/StoryRibbon';
@ -95,7 +95,7 @@ const ChatFolders: FC<OwnProps & StateProps> = ({
// eslint-disable-next-line no-null/no-null
const transitionRef = useRef<HTMLDivElement>(null);
const lang = useOldLang();
const lang = useLang();
useEffect(() => {
loadChatFolders();
@ -151,7 +151,7 @@ const ChatFolders: FC<OwnProps & StateProps> = ({
if (canShareFolder) {
contextActions.push({
title: lang('ChatList.ContextMenuShare'),
title: lang('FilterShare'),
icon: 'link',
handler: () => {
const chatListCount = Object.values(chatFoldersById).reduce((acc, el) => acc + (el.isChatList ? 1 : 0), 0);
@ -187,7 +187,7 @@ const ChatFolders: FC<OwnProps & StateProps> = ({
});
contextActions.push({
title: lang('FilterDeleteItem'),
title: lang('FilterDelete'),
icon: 'delete',
destructive: true,
handler: () => {

View File

@ -7,6 +7,7 @@ import React, {
} from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
import type { RegularLangKey } from '../../../types/language';
import { GlobalSearchContent } from '../../../types';
import { selectTabState } from '../../../global/selectors';
@ -14,8 +15,8 @@ import { parseDateString } from '../../../util/dates/dateFormat';
import useHistoryBack from '../../../hooks/useHistoryBack';
import useKeyboardListNavigation from '../../../hooks/useKeyboardListNavigation';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import useOldLang from '../../../hooks/useOldLang';
import TabList from '../../ui/TabList';
import Transition from '../../ui/Transition';
@ -41,19 +42,24 @@ type StateProps = {
chatId?: string;
};
const TABS = [
{ type: GlobalSearchContent.ChatList, title: 'SearchAllChatsShort' },
{ type: GlobalSearchContent.ChannelList, title: 'ChannelsTab' },
{ type: GlobalSearchContent.BotApps, title: 'AppsTab' },
{ type: GlobalSearchContent.Media, title: 'SharedMediaTab2' },
{ type: GlobalSearchContent.Links, title: 'SharedLinksTab2' },
{ type: GlobalSearchContent.Files, title: 'SharedFilesTab2' },
{ type: GlobalSearchContent.Music, title: 'SharedMusicTab2' },
{ type: GlobalSearchContent.Voice, title: 'SharedVoiceTab2' },
type TabInfo = {
type: GlobalSearchContent;
key: RegularLangKey;
};
const TABS: TabInfo[] = [
{ type: GlobalSearchContent.ChatList, key: 'SearchTabChats' },
{ type: GlobalSearchContent.ChannelList, key: 'SearchTabChannels' },
{ type: GlobalSearchContent.BotApps, key: 'SearchTabApps' },
{ type: GlobalSearchContent.Media, key: 'SearchTabMedia' },
{ type: GlobalSearchContent.Links, key: 'SearchTabLinks' },
{ type: GlobalSearchContent.Files, key: 'SearchTabFiles' },
{ type: GlobalSearchContent.Music, key: 'SearchTabMusic' },
{ type: GlobalSearchContent.Voice, key: 'SearchTabVoice' },
];
const CHAT_TABS = [
{ type: GlobalSearchContent.ChatList, title: 'All Messages' },
const CHAT_TABS: TabInfo[] = [
{ type: GlobalSearchContent.ChatList, key: 'SearchTabMessages' },
...TABS.slice(3), // Skip ChatList, ChannelList and BotApps, replaced with All Messages
];
@ -70,11 +76,17 @@ const LeftSearch: FC<OwnProps & StateProps> = ({
setGlobalSearchDate,
} = getActions();
const lang = useOldLang();
const lang = useLang();
const [activeTab, setActiveTab] = useState(currentContent);
const dateSearchQuery = useMemo(() => parseDateString(searchQuery), [searchQuery]);
const tabs = chatId ? CHAT_TABS : TABS;
const tabs = useMemo(() => {
const arr = chatId ? CHAT_TABS : TABS;
return arr.map((tab) => ({
...tab,
title: lang(tab.key),
}));
}, [chatId, lang]);
const handleSwitchTab = useLastCallback((index: number) => {
const tab = tabs[index];

View File

@ -5,6 +5,7 @@ import { getActions, getGlobal, withGlobal } from '../../../global';
import type { ApiStarTopupOption } from '../../../api/types';
import type { GlobalState, TabState } from '../../../global/types';
import type { RegularLangKey } from '../../../types/language';
import { getChatTitle, getUserFullName } from '../../../global/helpers';
import { selectChat, selectIsPremiumPurchaseBlocked, selectUser } from '../../../global/selectors';
@ -35,10 +36,10 @@ import StarLogo from '../../../assets/icons/StarLogo.svg';
import StarsBackground from '../../../assets/stars-bg.png';
const TRANSACTION_TYPES = ['all', 'inbound', 'outbound'] as const;
const TRANSACTION_TABS: TabWithProperties[] = [
{ title: 'StarsTransactionsAll' },
{ title: 'StarsTransactionsIncoming' },
{ title: 'StarsTransactionsOutgoing' },
const TRANSACTION_TABS_KEYS: RegularLangKey[] = [
'StarsTransactionsAll',
'StarsTransactionsIncoming',
'StarsTransactionsOutgoing',
];
const TRANSACTION_ITEM_CLASS = 'StarsTransactionItem';
const SUBSCRIPTION_PURPOSE = 'subs';
@ -113,6 +114,12 @@ const StarsBalanceModal = ({
const shouldShowItems = Boolean(history?.all?.transactions.length && !shouldOpenOnBuy);
const shouldSuggestGifting = !shouldOpenOnBuy;
const transactionTabs: TabWithProperties[] = useMemo(() => {
return TRANSACTION_TABS_KEYS.map((key) => ({
title: lang(key),
}));
}, [lang]);
useEffect(() => {
if (!isOpen) {
setHeaderHidden(true);
@ -266,7 +273,7 @@ const StarsBalanceModal = ({
<Transition
name={lang.isRtl ? 'slideOptimizedRtl' : 'slideOptimized'}
activeKey={selectedTabIndex}
renderCount={TRANSACTION_TABS.length}
renderCount={TRANSACTION_TABS_KEYS.length}
shouldRestoreHeight
className={styles.transition}
>
@ -292,7 +299,7 @@ const StarsBalanceModal = ({
className={styles.tabs}
tabClassName={styles.tab}
activeTab={selectedTabIndex}
tabs={TRANSACTION_TABS}
tabs={transactionTabs}
onSwitchTab={setSelectedTabIndex}
/>
</div>

View File

@ -19,6 +19,7 @@ import type { TabState } from '../../global/types';
import type {
ISettings, ProfileState, ProfileTabType, SharedMediaType, ThreadId,
} from '../../types';
import type { RegularLangKey } from '../../types/language';
import { MAIN_THREAD_ID } from '../../api/types';
import { AudioOrigin, MediaViewerOrigin, NewChatMembersProgress } from '../../types';
@ -68,6 +69,7 @@ import useCacheBuster from '../../hooks/useCacheBuster';
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
import useFlag from '../../hooks/useFlag';
import { useIntersectionObserver } from '../../hooks/useIntersectionObserver';
import useLang from '../../hooks/useLang';
import useLastCallback from '../../hooks/useLastCallback';
import useOldLang from '../../hooks/useOldLang';
import useAsyncRendering from './hooks/useAsyncRendering';
@ -151,14 +153,14 @@ type StateProps = {
type TabProps = {
type: ProfileTabType;
title: string;
key: RegularLangKey;
};
const TABS: TabProps[] = [
{ type: 'media', title: 'SharedMediaTab2' },
{ type: 'documents', title: 'SharedFilesTab2' },
{ type: 'links', title: 'SharedLinksTab2' },
{ type: 'audio', title: 'SharedMusicTab2' },
{ type: 'media', key: 'ProfileTabMedia' },
{ type: 'documents', key: 'ProfileTabFiles' },
{ type: 'links', key: 'ProfileTabLinks' },
{ type: 'audio', key: 'ProfileTabMusic' },
];
const HIDDEN_RENDER_DELAY = 1000;
@ -231,42 +233,63 @@ const Profile: FC<OwnProps & StateProps> = ({
const containerRef = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null
const transitionRef = useRef<HTMLDivElement>(null);
const lang = useOldLang();
const oldLang = useOldLang();
const lang = useLang();
const [deletingUserId, setDeletingUserId] = useState<string | undefined>();
const profileId = isSavedDialog ? String(threadId) : chatId;
const isSavedMessages = profileId === currentUserId && !isSavedDialog;
const tabs = useMemo(() => ([
...(isSavedMessages && !isSavedDialog ? [{ type: 'dialogs' as const, title: 'SavedDialogsTab' }] : []),
...(hasStoriesTab ? [{ type: 'stories' as const, title: 'ProfileStories' }] : []),
...(hasStoriesTab && isSavedMessages ? [{ type: 'storiesArchive' as const, title: 'ProfileStoriesArchive' }] : []),
...(hasGiftsTab ? [{ type: 'gifts' as const, title: 'ProfileGifts' }] : []),
...(hasMembersTab ? [{
type: 'members' as const, title: isChannel ? 'ChannelSubscribers' : 'GroupMembers',
}] : []),
...(hasPreviewMediaTab ? [{
type: 'previewMedia' as const, title: 'ProfileBotPreviewTab',
}] : []),
...TABS,
// TODO The filter for voice messages currently does not work
// in forum topics. Return it when it's fixed on the server side.
...(!isTopicInfo ? [{ type: 'voice' as const, title: 'SharedVoiceTab2' }] : []),
...(hasCommonChatsTab ? [{ type: 'commonChats' as const, title: 'SharedGroupsTab2' }] : []),
...(isChannel && similarChannels?.length
? [{ type: 'similarChannels' as const, title: 'SimilarChannelsTab' }]
: []),
]), [
hasCommonChatsTab,
hasMembersTab,
hasPreviewMediaTab,
hasStoriesTab,
hasGiftsTab,
isChannel,
isTopicInfo,
similarChannels,
isSavedMessages,
isSavedDialog,
const tabs = useMemo(() => {
const arr: TabProps[] = [];
if (isSavedMessages && !isSavedDialog) {
arr.push({ type: 'dialogs', key: 'ProfileTabSavedDialogs' });
}
if (hasStoriesTab) {
arr.push({ type: 'stories', key: 'ProfileTabStories' });
}
if (hasStoriesTab && isSavedMessages) {
arr.push({ type: 'storiesArchive', key: 'ProfileTabStoriesArchive' });
}
if (hasGiftsTab) {
arr.push({ type: 'gifts', key: 'ProfileTabGifts' });
}
if (hasMembersTab) {
arr.push({ type: 'members', key: isChannel ? 'ProfileTabSubscribers' : 'ProfileTabMembers' });
}
if (hasPreviewMediaTab) {
arr.push({ type: 'previewMedia', key: 'ProfileTabBotPreview' });
}
arr.push(...TABS);
// Voice messages filter currently does not work in forum topics. Return it when it's fixed on the server side.
if (!isTopicInfo) {
arr.push({ type: 'voice', key: 'ProfileTabVoice' });
}
if (hasCommonChatsTab) {
arr.push({ type: 'commonChats', key: 'ProfileTabSharedGroups' });
}
if (isChannel && similarChannels?.length) {
arr.push({ type: 'similarChannels', key: 'ProfileTabSimilarChannels' });
}
return arr.map((tab) => ({
type: tab.type,
title: lang(tab.key),
}));
}, [
isSavedMessages, isSavedDialog, hasStoriesTab, hasGiftsTab, hasMembersTab, hasPreviewMediaTab, isTopicInfo,
hasCommonChatsTab, isChannel, similarChannels?.length, lang,
]);
const initialTab = useMemo(() => {
@ -471,7 +494,7 @@ const Profile: FC<OwnProps & StateProps> = ({
function getMemberContextAction(memberId: string): MenuItemContextAction[] | undefined {
return memberId === currentUserId || !canDeleteMembers ? undefined : [{
title: lang('lng_context_remove_from_group'),
title: oldLang('lng_context_remove_from_group'),
icon: 'stop',
handler: () => {
setDeletingUserId(memberId);
@ -506,28 +529,28 @@ const Profile: FC<OwnProps & StateProps> = ({
text = areMembersHidden ? 'You have no access to group members list.' : 'No members found';
break;
case 'commonChats':
text = lang('NoGroupsInCommon');
text = oldLang('NoGroupsInCommon');
break;
case 'documents':
text = lang('lng_media_file_empty');
text = oldLang('lng_media_file_empty');
break;
case 'links':
text = lang('lng_media_link_empty');
text = oldLang('lng_media_link_empty');
break;
case 'audio':
text = lang('lng_media_song_empty');
text = oldLang('lng_media_song_empty');
break;
case 'voice':
text = lang('lng_media_audio_empty');
text = oldLang('lng_media_audio_empty');
break;
case 'stories':
text = lang('StoryList.SavedEmptyState.Title');
text = oldLang('StoryList.SavedEmptyState.Title');
break;
case 'storiesArchive':
text = lang('StoryList.ArchivedEmptyState.Title');
text = oldLang('StoryList.ArchivedEmptyState.Title');
break;
default:
text = lang('SharedMedia.EmptyTitle');
text = oldLang('SharedMedia.EmptyTitle');
}
return (
@ -540,7 +563,7 @@ const Profile: FC<OwnProps & StateProps> = ({
return (
<div
className={`content ${resultType}-list`}
dir={lang.isRtl && resultType === 'media' ? 'rtl' : undefined}
dir={oldLang.isRtl && resultType === 'media' ? 'rtl' : undefined}
teactFastList
>
{resultType === 'media' ? (
@ -612,7 +635,7 @@ const Profile: FC<OwnProps & StateProps> = ({
key={id}
theme={theme}
message={messagesById[id]}
senderTitle={getSenderName(lang, messagesById[id], chatsById, usersById)}
senderTitle={getSenderName(oldLang, messagesById[id], chatsById, usersById)}
origin={AudioOrigin.SharedMedia}
date={messagesById[id].date}
className="scroll-item"
@ -679,11 +702,11 @@ const Profile: FC<OwnProps & StateProps> = ({
<>
{/* eslint-disable-next-line react/jsx-no-bind */}
<Button className="show-more-channels" size="smaller" onClick={() => openPremiumModal()}>
{lang('UnlockSimilar')}
{oldLang('UnlockSimilar')}
<i className="icon icon-unlock-badge" />
</Button>
<div className="more-similar">
{renderText(lang('MoreSimilarText', limitSimilarChannels), ['simple_markdown'])}
{renderText(oldLang('MoreSimilarText', limitSimilarChannels), ['simple_markdown'])}
</div>
</>
)}
@ -721,7 +744,7 @@ const Profile: FC<OwnProps & StateProps> = ({
>
<Transition
ref={transitionRef}
name={lang.isRtl ? 'slideOptimizedRtl' : 'slideOptimized'}
name={oldLang.isRtl ? 'slideOptimizedRtl' : 'slideOptimized'}
activeKey={activeKey}
renderCount={tabs.length}
shouldRestoreHeight
@ -739,7 +762,7 @@ const Profile: FC<OwnProps & StateProps> = ({
<FloatingActionButton
isShown={resultType === 'members'}
onClick={handleNewMemberDialogOpen}
ariaLabel={lang('lng_channel_add_users')}
ariaLabel={oldLang('lng_channel_add_users')}
>
<i className="icon icon-add-user-filled" />
</FloatingActionButton>

View File

@ -408,6 +408,8 @@ export interface LangPair {
'PasscodeControllerChangeTitle': undefined;
'FilterNew': undefined;
'FilterEdit': undefined;
'FilterDelete': undefined;
'FilterShare': undefined;
'AutoDeleteConfirm': undefined;
'LogOutTitle': undefined;
'AccDescrGoBack': undefined;
@ -1172,6 +1174,32 @@ export interface LangPair {
'PrivateChatsSearchContext': undefined;
'GroupChatsSearchContext': undefined;
'ChannelsSearchContext': undefined;
'SearchTabChats': undefined;
'SearchTabChannels': undefined;
'SearchTabApps': undefined;
'SearchTabMedia': undefined;
'SearchTabLinks': undefined;
'SearchTabFiles': undefined;
'SearchTabMusic': undefined;
'SearchTabVoice': undefined;
'SearchTabMessages': undefined;
'StarsTransactionsAll': undefined;
'StarsTransactionsIncoming': undefined;
'StarsTransactionsOutgoing': undefined;
'ProfileTabSavedDialogs': undefined;
'ProfileTabStories': undefined;
'ProfileTabStoriesArchive': undefined;
'ProfileTabGifts': undefined;
'ProfileTabSubscribers': undefined;
'ProfileTabMembers': undefined;
'ProfileTabBotPreview': undefined;
'ProfileTabMedia': undefined;
'ProfileTabFiles': undefined;
'ProfileTabLinks': undefined;
'ProfileTabMusic': undefined;
'ProfileTabVoice': undefined;
'ProfileTabSharedGroups': undefined;
'ProfileTabSimilarChannels': undefined;
}
export interface LangPairWithVariables<V extends unknown = LangVariable> {