diff --git a/public/locales/en.json b/public/locales/en.json
index 5bd20971..98695262 100644
--- a/public/locales/en.json
+++ b/public/locales/en.json
@@ -507,5 +507,52 @@
"unverified_device": "Unverified Device",
"unverified_devices": "Unverified Devices"
+ },
+
+ "Explore": {
+ "explore_community": "Explore Community",
+
+ "add_server": "Add Server",
+ "add_server_desc": "Add server name to explore public communities.",
+ "server_name": "Server Name",
+ "failed_load_public_rooms": "Failed to load public rooms. Please try again.",
+ "view": "View",
+ "featured": "Featured",
+ "servers": "Servers",
+
+ "featured_by_client": "Featured by Client",
+ "featured_by_client_desc": "Public rooms and spaces hand-picked by this client.",
+ "featured_spaces": "Featured Spaces",
+ "featured_rooms": "Featured Rooms",
+ "no_featured": "No featured rooms or spaces yet.",
+
+ "search": "Search",
+ "search_placeholder": "Search for keyword",
+ "clear": "Clear",
+ "enter": "Enter",
+ "protocols": "Protocols",
+ "presets": "Presets",
+ "custom_limit": "Custom Limit",
+ "per_page_limit": "Per Page Item Limit",
+ "change_limit": "Change Limit",
+ "page_limit": "Page Limit: {{limit}}",
+ "results_for": "Results for \"{{term}}\"",
+ "popular_communities": "Popular Communities",
+ "filter_all": "All",
+ "filter_spaces": "Spaces",
+ "filter_rooms": "Rooms",
+ "previous_page": "Previous Page",
+ "next_page": "Next Page",
+ "no_communities": "No communities found!",
+
+ "space_badge": "Space",
+ "members_count": "{{count}} Members",
+ "join": "Join",
+ "joining": "Joining",
+ "retry": "Retry",
+ "join_error": "Join Error",
+ "join_error_unknown": "Failed to join. Unknown Error.",
+ "view_error": "View Error",
+ "cancel": "Cancel"
}
}
diff --git a/public/locales/ru.json b/public/locales/ru.json
index 2361c3de..a506fb2b 100644
--- a/public/locales/ru.json
+++ b/public/locales/ru.json
@@ -509,5 +509,52 @@
"unverified_device": "Неподтверждённое устройство",
"unverified_devices": "Неподтверждённые устройства"
+ },
+
+ "Explore": {
+ "explore_community": "Обзор сообществ",
+
+ "add_server": "Добавить сервер",
+ "add_server_desc": "Укажите имя сервера для обзора публичных сообществ.",
+ "server_name": "Имя сервера",
+ "failed_load_public_rooms": "Не удалось загрузить публичные комнаты. Попробуйте ещё раз.",
+ "view": "Открыть",
+ "featured": "Рекомендуемые",
+ "servers": "Серверы",
+
+ "featured_by_client": "Рекомендации клиента",
+ "featured_by_client_desc": "Подборка публичных комнат и пространств от этого клиента.",
+ "featured_spaces": "Рекомендуемые пространства",
+ "featured_rooms": "Рекомендуемые комнаты",
+ "no_featured": "Рекомендуемых комнат и пространств пока нет.",
+
+ "search": "Поиск",
+ "search_placeholder": "Поиск по ключевому слову",
+ "clear": "Очистить",
+ "enter": "Найти",
+ "protocols": "Протоколы",
+ "presets": "Готовые значения",
+ "custom_limit": "Своё значение",
+ "per_page_limit": "Элементов на странице",
+ "change_limit": "Применить",
+ "page_limit": "На странице: {{limit}}",
+ "results_for": "Результаты для «{{term}}»",
+ "popular_communities": "Популярные сообщества",
+ "filter_all": "Все",
+ "filter_spaces": "Пространства",
+ "filter_rooms": "Комнаты",
+ "previous_page": "Предыдущая",
+ "next_page": "Следующая",
+ "no_communities": "Сообщества не найдены!",
+
+ "space_badge": "Пространство",
+ "members_count": "{{count}} участников",
+ "join": "Присоединиться",
+ "joining": "Вступление…",
+ "retry": "Повторить",
+ "join_error": "Не удалось вступить",
+ "join_error_unknown": "Не удалось присоединиться. Неизвестная ошибка.",
+ "view_error": "Подробности",
+ "cancel": "Отмена"
}
}
diff --git a/src/app/components/room-card/RoomCard.tsx b/src/app/components/room-card/RoomCard.tsx
index 34a7e24b..38b19fa3 100644
--- a/src/app/components/room-card/RoomCard.tsx
+++ b/src/app/components/room-card/RoomCard.tsx
@@ -19,6 +19,7 @@ import {
} from 'folds';
import classNames from 'classnames';
import FocusTrap from 'focus-trap-react';
+import { useTranslation } from 'react-i18next';
import * as css from './style.css';
import { RoomAvatar } from '../room-avatar';
import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
@@ -94,6 +95,7 @@ function ErrorDialog({
message: string;
children: (openError: () => void) => ReactNode;
}) {
+ const { t } = useTranslation();
const [viewError, setViewError] = useState(false);
const closeError = () => setViewError(false);
const openError = () => setViewError(true);
@@ -120,7 +122,7 @@ function ErrorDialog({
@@ -161,6 +163,7 @@ export const RoomCard = as<'div', RoomCardProps>(
},
ref
) => {
+ const { t } = useTranslation();
const mx = useMatrixClient();
const useAuthentication = useMediaAuthentication();
const joinedRoomId = useJoinedRoomId(allRooms, roomIdOrAlias);
@@ -224,7 +227,7 @@ export const RoomCard = as<'div', RoomCardProps>(
{(roomType === RoomType.Space || joinedRoom?.isSpaceRoom()) && (
- Space
+ {t('Explore.space_badge')}
)}
@@ -252,7 +255,7 @@ export const RoomCard = as<'div', RoomCardProps>(
{typeof joinedMemberCount === 'number' && (
- {`${millify(joinedMemberCount)} Members`}
+ {t('Explore.members_count', { count: millify(joinedMemberCount) })}
)}
{typeof joinedRoomId === 'string' && (
@@ -263,7 +266,7 @@ export const RoomCard = as<'div', RoomCardProps>(
size="300"
>
- View
+ {t('Explore.view')}
)}
@@ -276,7 +279,7 @@ export const RoomCard = as<'div', RoomCardProps>(
before={joining && }
>
- {joining ? 'Joining' : 'Join'}
+ {joining ? t('Explore.joining') : t('Explore.join')}
)}
@@ -290,12 +293,12 @@ export const RoomCard = as<'div', RoomCardProps>(
size="300"
>
- Retry
+ {t('Explore.retry')}
{(openError) => (
)}
diff --git a/src/app/pages/client/explore/Explore.tsx b/src/app/pages/client/explore/Explore.tsx
index dae83166..47247931 100644
--- a/src/app/pages/client/explore/Explore.tsx
+++ b/src/app/pages/client/explore/Explore.tsx
@@ -1,6 +1,7 @@
import React, { FormEventHandler, useCallback, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import FocusTrap from 'focus-trap-react';
+import { useTranslation } from 'react-i18next';
import {
Avatar,
Box,
@@ -39,6 +40,7 @@ import { PageNav, PageNavContent, PageNavHeader } from '../../../components/page
import { stopPropagation } from '../../../utils/keyboard';
export function AddServer() {
+ const { t } = useTranslation();
const mx = useMatrixClient();
const navigate = useNavigate();
const [dialog, setDialog] = useState(false);
@@ -94,7 +96,7 @@ export function AddServer() {
size="500"
>
- Add Server
+ {t('Explore.add_server')}
setDialog(false)} radii="300">
@@ -107,13 +109,13 @@ export function AddServer() {
direction="Column"
gap="400"
>
- Add server name to explore public communities.
+ {t('Explore.add_server_desc')}
- Server Name
+ {t('Explore.server_name')}
{exploreState.status === AsyncStatus.Error && (
- Failed to load public rooms. Please try again.
+ {t('Explore.failed_load_public_rooms')}
)}
@@ -132,7 +134,7 @@ export function AddServer() {
*/}
@@ -148,7 +150,7 @@ export function AddServer() {
onClick={() => setDialog(true)}
>
- Add Server
+ {t('Explore.add_server')}
>
@@ -156,6 +158,7 @@ export function AddServer() {
}
export function Explore() {
+ const { t } = useTranslation();
const mx = useMatrixClient();
useNavToActivePathMapper('explore');
const userId = mx.getUserId();
@@ -173,7 +176,7 @@ export function Explore() {
- Explore Community
+ {t('Explore.explore_community')}
@@ -191,7 +194,7 @@ export function Explore() {
- Featured
+ {t('Explore.featured')}
@@ -229,7 +232,7 @@ export function Explore() {
- Servers
+ {t('Explore.servers')}
{servers.map((server) => (
diff --git a/src/app/pages/client/explore/Featured.tsx b/src/app/pages/client/explore/Featured.tsx
index f056cbb5..ee4d4e38 100644
--- a/src/app/pages/client/explore/Featured.tsx
+++ b/src/app/pages/client/explore/Featured.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
+import { useTranslation } from 'react-i18next';
import { useAtomValue } from 'jotai';
import { useClientConfig } from '../../../hooks/useClientConfig';
import { RoomCard, RoomCardGrid } from '../../../components/room-card';
@@ -20,6 +21,7 @@ import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
import { BackRouteHandler } from '../../../components/BackRouteHandler';
export function FeaturedRooms() {
+ const { t } = useTranslation();
const { featuredCommunities } = useClientConfig();
const { rooms, spaces } = featuredCommunities ?? {};
const allRooms = useAtomValue(allRoomsAtom);
@@ -49,14 +51,14 @@ export function FeaturedRooms() {
}
- title="Featured by Client"
- subTitle="Find and explore public rooms and spaces featured by client provider."
+ title={t('Explore.featured_by_client')}
+ subTitle={t('Explore.featured_by_client_desc')}
/>
{spaces && spaces.length > 0 && (
- Featured Spaces
+ {t('Explore.featured_spaces')}
{spaces.map((roomIdOrAlias) => (
@@ -85,7 +87,7 @@ export function FeaturedRooms() {
)}
{rooms && rooms.length > 0 && (
- Featured Rooms
+ {t('Explore.featured_rooms')}
{rooms.map((roomIdOrAlias) => (
@@ -123,7 +125,7 @@ export function FeaturedRooms() {
>
- No rooms or spaces featured by client provider.
+ {t('Explore.no_featured')}
)}
diff --git a/src/app/pages/client/explore/Server.tsx b/src/app/pages/client/explore/Server.tsx
index 48f267cc..eaeb35f7 100644
--- a/src/app/pages/client/explore/Server.tsx
+++ b/src/app/pages/client/explore/Server.tsx
@@ -29,6 +29,7 @@ import {
} from 'folds';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import FocusTrap from 'focus-trap-react';
+import { useTranslation } from 'react-i18next';
import { useAtomValue } from 'jotai';
import { useQuery } from '@tanstack/react-query';
import { MatrixClient, Method, RoomType } from 'matrix-js-sdk';
@@ -62,24 +63,26 @@ type RoomTypeFilter = {
title: string;
value: string | undefined;
};
-const useRoomTypeFilters = (): RoomTypeFilter[] =>
- useMemo(
+const useRoomTypeFilters = (): RoomTypeFilter[] => {
+ const { t } = useTranslation();
+ return useMemo(
() => [
{
- title: 'All',
+ title: t('Explore.filter_all'),
value: undefined,
},
{
- title: 'Spaces',
+ title: t('Explore.filter_spaces'),
value: RoomType.Space,
},
{
- title: 'Rooms',
+ title: t('Explore.filter_rooms'),
value: 'null',
},
],
- []
+ [t]
);
+};
const FALLBACK_ROOMS_LIMIT = 24;
@@ -91,6 +94,7 @@ type SearchProps = {
onReset: () => void;
};
function Search({ active, loading, searchInputRef, onSearch, onReset }: SearchProps) {
+ const { t } = useTranslation();
const handleSearchSubmit: FormEventHandler = (evt) => {
evt.preventDefault();
const { searchInput } = evt.target as HTMLFormElement & {
@@ -106,14 +110,14 @@ function Search({ active, loading, searchInputRef, onSearch, onReset }: SearchPr
return (
- Search
+ {t('Explore.search')}
@@ -132,11 +136,11 @@ function Search({ active, loading, searchInputRef, onSearch, onReset }: SearchPr
after={}
onClick={onReset}
>
- Clear
+ {t('Explore.clear')}
) : (
- Enter
+ {t('Explore.enter')}
)
}
@@ -153,6 +157,7 @@ function ThirdPartyProtocolsSelector({
instanceId?: string;
onChange: (instanceId?: string) => void;
}) {
+ const { t } = useTranslation();
const mx = useMatrixClient();
const [menuAnchor, setMenuAnchor] = useState();
@@ -196,7 +201,7 @@ function ThirdPartyProtocolsSelector({
style={{ padding: config.space.S100, minWidth: toRem(100) }}
>
- Protocols
+ {t('Explore.protocols')}