diff --git a/public/locales/en.json b/public/locales/en.json index fa79e936..f0ce19b0 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -279,5 +279,36 @@ "events": "Events", "total": "Total: {{count}}", "add_new": "Add New" + }, + "Search": { + "search": "Search", + "no_match_found": "No Match Found", + "no_rooms": "No Rooms", + "no_match_for_query": "No match found for \"{{query}}\".", + "no_rooms_to_display": "You do not have any rooms to display yet.", + "help_text": "Type # for rooms, @ for DMs and * for spaces. Hotkey: {{hotkey}}", + "message_search": "Message Search", + "message_search_subtitle": "Find helpful messages in your community by searching with related keywords.", + "no_results_for": "No results found for \"{{term}}\"", + "results_for": "Results for \"{{term}}\"", + "search_for_keyword": "Search for keyword", + "clear": "Clear", + "enter": "Enter", + "sort_by": "Sort by", + "recent": "Recent", + "relevance": "Relevance", + "rooms": "Rooms", + "rooms_for_query": "Rooms for \"{{query}}\"", + "no_match_found_excl": "No match found!", + "save": "Save", + "save_count": "Save ({{count}})", + "deselect_all": "Deselect All", + "select_rooms": "Select Rooms", + "filter": "Filter", + "global": "Global", + "room_tombstone": "This room has been replaced.", + "event": "event", + "open": "Open", + "home": "Home" } } diff --git a/public/locales/ru.json b/public/locales/ru.json index f4dfbf59..9c29867a 100644 --- a/public/locales/ru.json +++ b/public/locales/ru.json @@ -279,5 +279,36 @@ "events": "События", "total": "Всего: {{count}}", "add_new": "Добавить" + }, + "Search": { + "search": "Поиск", + "no_match_found": "Совпадений не найдено", + "no_rooms": "Нет комнат", + "no_match_for_query": "Совпадений для «{{query}}» не найдено.", + "no_rooms_to_display": "У вас пока нет комнат для отображения.", + "help_text": "Введите # для комнат, @ для личных чатов и * для пространств. Горячая клавиша: {{hotkey}}", + "message_search": "Поиск сообщений", + "message_search_subtitle": "Находите нужные сообщения в сообществе по ключевым словам.", + "no_results_for": "Ничего не найдено по запросу «{{term}}»", + "results_for": "Результаты для «{{term}}»", + "search_for_keyword": "Поиск по ключевому слову", + "clear": "Очистить", + "enter": "Найти", + "sort_by": "Сортировка", + "recent": "По дате", + "relevance": "По релевантности", + "rooms": "Комнаты", + "rooms_for_query": "Комнаты для «{{query}}»", + "no_match_found_excl": "Совпадений не найдено!", + "save": "Сохранить", + "save_count": "Сохранить ({{count}})", + "deselect_all": "Снять выбор", + "select_rooms": "Выбрать комнаты", + "filter": "Фильтр", + "global": "Глобальный", + "room_tombstone": "Комната перенесена.", + "event": "событие", + "open": "Открыть", + "home": "Главная" } } diff --git a/src/app/features/message-search/MessageSearch.tsx b/src/app/features/message-search/MessageSearch.tsx index 26085b5f..4fa8ce24 100644 --- a/src/app/features/message-search/MessageSearch.tsx +++ b/src/app/features/message-search/MessageSearch.tsx @@ -1,5 +1,6 @@ import React, { RefObject, useEffect, useMemo, useRef } from 'react'; import { Text, Box, Icon, Icons, config, Spinner, IconButton, Line, toRem } from 'folds'; +import { Trans, useTranslation } from 'react-i18next'; import { useAtomValue } from 'jotai'; import { useVirtualizer } from '@tanstack/react-virtual'; import { useInfiniteQuery } from '@tanstack/react-query'; @@ -50,6 +51,7 @@ export function MessageSearch({ senders, scrollRef, }: MessageSearchProps) { + const { t } = useTranslation(); const mx = useMatrixClient(); const mDirects = useAtomValue(mDirectAtom); const allRooms = useRooms(mx, allRoomsAtom, mDirects); @@ -229,8 +231,8 @@ export function MessageSearch({ } - title="Search Messages" - subTitle="Find helpful messages in your community by searching with related keywords." + title={t('Search.message_search')} + subTitle={t('Search.message_search_subtitle')} /> @@ -245,7 +247,11 @@ export function MessageSearch({ > - No results found for {`"${msgSearchParams.term}"`} + }} + /> )} @@ -262,7 +268,7 @@ export function MessageSearch({ {vItems.length > 0 && ( - {`Results for "${msgSearchParams.term}"`} + {t('Search.results_for', { term: msgSearchParams.term })}
void; }; function OrderButton({ order, onChange }: OrderButtonProps) { + const { t } = useTranslation(); const [menuAnchor, setMenuAnchor] = useState(); const rankOrder = order === SearchOrderBy.Rank; @@ -72,7 +74,7 @@ function OrderButton({ order, onChange }: OrderButtonProps) { >
- Sort by + {t('Search.sort_by')}
@@ -83,7 +85,7 @@ function OrderButton({ order, onChange }: OrderButtonProps) { radii="300" aria-pressed={!rankOrder} > - Recent + {t('Search.recent')} setOrder(SearchOrderBy.Rank)} @@ -92,7 +94,7 @@ function OrderButton({ order, onChange }: OrderButtonProps) { radii="300" aria-pressed={rankOrder} > - Relevance + {t('Search.relevance')}
@@ -105,7 +107,7 @@ function OrderButton({ order, onChange }: OrderButtonProps) { after={} onClick={handleOpenMenu} > - {rankOrder ? Relevance : Recent} + {rankOrder ? {t('Search.relevance')} : {t('Search.recent')}} ); @@ -127,6 +129,7 @@ type SelectRoomButtonProps = { onChange: (rooms?: string[]) => void; }; function SelectRoomButton({ roomList, selectedRooms, onChange }: SelectRoomButtonProps) { + const { t } = useTranslation(); const mx = useMatrixClient(); const scrollRef = useRef(null); const [menuAnchor, setMenuAnchor] = useState(); @@ -215,7 +218,7 @@ function SelectRoomButton({ roomList, selectedRooms, onChange }: SelectRoomButto gap="100" style={{ padding: config.space.S200, paddingBottom: 0 }} > - Search + {t('Search.search')} - {!searchResult && Rooms} - {searchResult && {`Rooms for "${searchResult.query}"`}} + {!searchResult && {t('Search.rooms')}} + {searchResult && {t('Search.rooms_for_query', { query: searchResult.query })}} {searchResult && searchResult.items.length === 0 && ( - No match found! + {t('Search.no_match_found_excl')} )}
@@ -319,7 +322,7 @@ function SelectRoomButton({ roomList, selectedRooms, onChange }: SelectRoomButto radii="Pill" before={} > - Select Rooms + {t('Search.select_rooms')} ); @@ -347,11 +350,12 @@ export function SearchFilters({ onGlobalChange, onOrderChange, }: SearchFiltersProps) { + const { t } = useTranslation(); const mx = useMatrixClient(); return ( - Filter + {t('Search.filter')} onGlobalChange(true)} > - Global + {t('Search.global')} )} void; }; export function SearchInput({ active, loading, searchInputRef, onSearch, onReset }: SearchProps) { + const { t } = useTranslation(); const handleSearchSubmit: FormEventHandler = (evt) => { evt.preventDefault(); const { searchInput } = evt.target as HTMLFormElement & { @@ -24,7 +26,7 @@ export function SearchInput({ active, loading, searchInputRef, onSearch, onReset return ( - Search + {t('Search.search')} } onClick={onReset} > - Clear + {t('Search.clear')} ) : ( - Enter + {t('Search.enter')} ) } diff --git a/src/app/features/message-search/SearchResultGroup.tsx b/src/app/features/message-search/SearchResultGroup.tsx index 14817cc4..39a153d9 100644 --- a/src/app/features/message-search/SearchResultGroup.tsx +++ b/src/app/features/message-search/SearchResultGroup.tsx @@ -3,6 +3,7 @@ import React, { MouseEventHandler, useMemo } from 'react'; import { IEventWithRoomId, JoinRule, RelationType, Room } from 'matrix-js-sdk'; import { HTMLReactParserOptions } from 'html-react-parser'; import { Avatar, Box, Chip, Header, Icon, Icons, Text, config } from 'folds'; +import { useTranslation } from 'react-i18next'; import { Opts as LinkifyOpts } from 'linkifyjs'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { @@ -74,6 +75,7 @@ export function SearchResultGroup({ hour24Clock, dateFormatString, }: SearchResultGroupProps) { + const { t } = useTranslation(); const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const highlightRegex = useMemo(() => makeHighlightRegex(highlights), [highlights]); @@ -165,7 +167,7 @@ export function SearchResultGroup({ return ( - Room Tombstone. {content.body} + {t('Search.room_tombstone')} {content.body} ); @@ -180,7 +182,7 @@ export function SearchResultGroup({ {event.type} - {' event'} + {` ${t('Search.event')}`} ); @@ -303,7 +305,7 @@ export function SearchResultGroup({ variant="Secondary" radii="400" > - Open + {t('Search.open')} diff --git a/src/app/features/search/Search.tsx b/src/app/features/search/Search.tsx index cfc4ee5f..34a594cf 100644 --- a/src/app/features/search/Search.tsx +++ b/src/app/features/search/Search.tsx @@ -25,6 +25,7 @@ import React, { useRef, useState, } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; import { isKeyHotkey } from 'is-hotkey'; import { useAtom, useAtomValue } from 'jotai'; import { Room } from 'matrix-js-sdk'; @@ -135,6 +136,7 @@ type SearchProps = { requestClose: () => void; }; export function Search({ requestClose }: SearchProps) { + const { t } = useTranslation(); const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const scrollRef = useRef(null); @@ -269,7 +271,7 @@ export function Search({ requestClose }: SearchProps) { variant="Background" radii="400" outlined - placeholder="Search" + placeholder={t('Search.search')} before={} onChange={handleInputChange} onKeyDown={handleInputKeyDown} @@ -286,12 +288,12 @@ export function Search({ requestClose }: SearchProps) { gap="100" > - {result ? 'No Match Found' : 'No Rooms'} + {result ? t('Search.no_match_found') : t('Search.no_rooms')} {result - ? `No match found for "${result.query}".` - : `You do not have any Rooms to display yet.`} + ? t('Search.no_match_for_query', { query: result.query }) + : t('Search.no_rooms_to_display')} )} @@ -409,8 +411,11 @@ export function Search({ requestClose }: SearchProps) { - Type # for rooms, @ for DMs and * for spaces. Hotkey:{' '} - {isMacOS() ? KeySymbol.Command : 'Ctrl'} + k + }} + /> diff --git a/src/app/pages/client/home/Search.tsx b/src/app/pages/client/home/Search.tsx index d5ddfb77..f0898109 100644 --- a/src/app/pages/client/home/Search.tsx +++ b/src/app/pages/client/home/Search.tsx @@ -1,5 +1,6 @@ import React, { useRef } from 'react'; import { Box, Icon, Icons, Text, Scroll, IconButton } from 'folds'; +import { useTranslation } from 'react-i18next'; import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page'; import { MessageSearch } from '../../../features/message-search'; import { useHomeRooms } from './useHomeRooms'; @@ -7,6 +8,7 @@ import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { BackRouteHandler } from '../../../components/BackRouteHandler'; export function HomeSearch() { + const { t } = useTranslation(); const scrollRef = useRef(null); const rooms = useHomeRooms(); const screenSize = useScreenSizeContext(); @@ -29,7 +31,7 @@ export function HomeSearch() { {screenSize !== ScreenSize.Mobile && } - Message Search + {t('Search.message_search')} @@ -40,7 +42,7 @@ export function HomeSearch() { setOpen(true); return ( - + {(triggerRef) => ( diff --git a/src/app/pages/client/space/Search.tsx b/src/app/pages/client/space/Search.tsx index 017262b5..f895acda 100644 --- a/src/app/pages/client/space/Search.tsx +++ b/src/app/pages/client/space/Search.tsx @@ -1,5 +1,6 @@ import React, { useRef } from 'react'; import { Box, Icon, Icons, Text, Scroll, IconButton } from 'folds'; +import { useTranslation } from 'react-i18next'; import { useAtomValue } from 'jotai'; import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page'; import { MessageSearch } from '../../../features/message-search'; @@ -13,6 +14,7 @@ import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { BackRouteHandler } from '../../../components/BackRouteHandler'; export function SpaceSearch() { + const { t } = useTranslation(); const mx = useMatrixClient(); const scrollRef = useRef(null); const space = useSpace(); @@ -44,7 +46,7 @@ export function SpaceSearch() { {screenSize !== ScreenSize.Mobile && } - Message Search + {t('Search.message_search')}