Add translations

This commit is contained in:
Nicola Benaglia 2025-05-10 11:22:15 +02:00
parent f1d62fe11b
commit 5f602442e4
8 changed files with 104 additions and 69 deletions

View File

@ -5,6 +5,7 @@
"backup_account": "backup account",
"backup_wallet": "backup wallet",
"cancel": "cancel",
"cancel_invitation": "cancel invitation",
"change": "change",
"change_language": "change language",
"choose": "choose",
@ -48,8 +49,11 @@
"publish": "publish fee"
},
"general_settings": "general settings",
"invite_list": "invite list",
"last_height": "last height",
"list": {
"invite": "invite list",
"join_request": "join request list"
},
"loading": "loading...",
"loading_posts": "loading posts... please wait.",
"message_us": "please message us on Telegram or Discord if you need 4 QORT to start chatting without any limitations",

View File

@ -31,6 +31,7 @@
"type": "group type"
},
"invitation_expiry": "invitation Expiry Time",
"invitees_list": "invitees list",
"join_requests": "join requests",
"question": {
"perform_transaction": "would you like to perform a {{action}} transaction?",
@ -72,10 +73,13 @@
"group_join_label": "joined group {{name}}: success!",
"group_join_request": "requested to join Group {{group_name}}: awaiting confirmation",
"group_join_outcome": "requested to join Group {{group_name}}: success!",
"invitation_cancellation": "successfully canceled invitation. It may take a couple of minutes for the changes to propagate",
"invitation_request": "accepted join request: awaiting confirmation",
"loading_threads": "loading threads... please wait.",
"post_creation": "successfully created post. It may take some time for the publish to propagate",
"thread_creation": "successfully created thread. It may take some time for the publish to propagate",
"unbanned_user": "successfully unbanned user. It may take a couple of minutes for the changes to propagate"
"unbanned_user": "successfully unbanned user. It may take a couple of minutes for the changes to propagate",
"user_joined": "user successfully joined!"
}
}
}

View File

@ -9,20 +9,12 @@ import {
Typography,
useTheme,
} from '@mui/material';
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ChatGroup } from '../Chat/ChatGroup';
import { CreateCommonSecret } from '../Chat/CreateCommonSecret';
import { base64ToUint8Array } from '../../qdn/encryption/group-encryption';
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
import CampaignIcon from '@mui/icons-material/Campaign';
import { AddGroup } from './AddGroup';
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
import CreateIcon from '@mui/icons-material/Create';
import {
AuthenticatedContainerInnerRight,
@ -52,7 +44,6 @@ import {
import { RequestQueueWithPromise } from '../../utils/queue/queue';
import { WebSocketActive } from './WebsocketActive';
import { useMessageQueue } from '../../MessageQueueContext';
import { ContextMenu } from '../ContextMenu';
import { HomeDesktop } from './HomeDesktop';
import { IconWrapper } from '../Desktop/DesktopFooter';
import { DesktopHeader } from '../Desktop/DesktopHeader';
@ -63,7 +54,6 @@ import { HubsIcon } from '../../assets/Icons/HubsIcon';
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
import { formatEmailDate } from './QMailMessages';
import { AdminSpace } from '../Chat/AdminSpace';
import {
addressInfoControllerAtom,
groupAnnouncementsAtom,
@ -77,9 +67,6 @@ import {
timestampEnterDataAtom,
} from '../../atoms/global';
import { sortArrayByTimestampAndGroupName } from '../../utils/time';
import PersonOffIcon from '@mui/icons-material/PersonOff';
import LockIcon from '@mui/icons-material/Lock';
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
import { BlockedUsersModal } from './BlockedUsersModal';
import { WalletsAppWrapper } from './WalletsAppWrapper';
import { useTranslation } from 'react-i18next';
@ -92,6 +79,7 @@ export const getPublishesFromAdmins = async (admins: string[], groupId) => {
groupId
}&exactmatchnames=true&limit=0&reverse=true&${queryString}&prefix=true`;
const response = await fetch(url);
if (!response.ok) {
throw new Error('network error');
}
@ -100,9 +88,11 @@ export const getPublishesFromAdmins = async (admins: string[], groupId) => {
const filterId = adminData.filter(
(data: any) => data.identifier === `symmetric-qchat-group-${groupId}`
);
if (filterId?.length === 0) {
return false;
}
const sortedData = filterId.sort((a: any, b: any) => {
// Get the most recent date for both a and b
const dateA = a.updated ? new Date(a.updated) : new Date(a.created);
@ -114,24 +104,18 @@ export const getPublishesFromAdmins = async (admins: string[], groupId) => {
return sortedData[0];
};
interface GroupProps {
myAddress: string;
isFocused: boolean;
userInfo: any;
balance: number;
isFocused: boolean;
myAddress: string;
userInfo: any;
}
export const timeDifferenceForNotificationChats = 900000;
export const requestQueueMemberNames = new RequestQueueWithPromise(5);
export const requestQueueAdminMemberNames = new RequestQueueWithPromise(5);
// const audio = new Audio(chrome.runtime?.getURL("msg-not1.wav"));
export const getGroupAdminsAddress = async (groupNumber: number) => {
// const validApi = await findUsableApi();
const response = await fetch(
`${getBaseApiReact()}/groups/members/${groupNumber}?limit=0&onlyAdmins=true`
);
@ -422,27 +406,24 @@ export const Group = ({
const [chatMode, setChatMode] = useState('groups');
const [newChat, setNewChat] = useState(false);
const [openSnack, setOpenSnack] = React.useState(false);
const [infoSnack, setInfoSnack] = React.useState(null);
const [isLoadingNotifyAdmin, setIsLoadingNotifyAdmin] = React.useState(false);
const [isLoadingGroups, setIsLoadingGroups] = React.useState(true);
const [isLoadingGroup, setIsLoadingGroup] = React.useState(false);
const [openSnack, setOpenSnack] = useState(false);
const [infoSnack, setInfoSnack] = useState(null);
const [isLoadingNotifyAdmin, setIsLoadingNotifyAdmin] = useState(false);
const [isLoadingGroups, setIsLoadingGroups] = useState(true);
const [isLoadingGroup, setIsLoadingGroup] = useState(false);
const [firstSecretKeyInCreation, setFirstSecretKeyInCreation] =
React.useState(false);
const [groupSection, setGroupSection] = React.useState('home');
useState(false);
const [groupSection, setGroupSection] = useState('home');
const [groupAnnouncements, setGroupAnnouncements] = useAtom(
groupAnnouncementsAtom
);
const [defaultThread, setDefaultThread] = React.useState(null);
const [isOpenDrawer, setIsOpenDrawer] = React.useState(false);
const [defaultThread, setDefaultThread] = useState(null);
const [isOpenDrawer, setIsOpenDrawer] = useState(false);
const setIsOpenBlockedUserModal = useSetAtom(isOpenBlockedModalAtom);
const [hideCommonKeyPopup, setHideCommonKeyPopup] = React.useState(false);
const [isLoadingGroupMessage, setIsLoadingGroupMessage] = React.useState('');
const [drawerMode, setDrawerMode] = React.useState('groups');
const [hideCommonKeyPopup, setHideCommonKeyPopup] = useState(false);
const [isLoadingGroupMessage, setIsLoadingGroupMessage] = useState('');
const [drawerMode, setDrawerMode] = useState('groups');
const setMutedGroups = useSetAtom(mutedGroupsAtom);
const [mobileViewMode, setMobileViewMode] = useState('home');
const [mobileViewModeKeepOpen, setMobileViewModeKeepOpen] = useState('');
const isFocusedRef = useRef(true);
@ -531,7 +512,10 @@ export const Group = ({
rej(response.error);
})
.catch((error) => {
rej(error.message || 'An error occurred');
rej(
error.message ||
t('core:message.error.generic', { postProcess: 'capitalize' })
);
});
});
} catch (error) {
@ -557,7 +541,10 @@ export const Group = ({
rej(response.error);
})
.catch((error) => {
rej(error.message || 'An error occurred');
rej(
error.message ||
t('core:message.error.generic', { postProcess: 'capitalize' })
);
});
});
} catch (error) {
@ -586,7 +573,10 @@ export const Group = ({
rej(response.error);
})
.catch((error) => {
rej(error.message || 'An error occurred');
rej(
error.message ||
t('core:message.error.generic', { postProcess: 'capitalize' })
);
});
});
} catch (error) {
@ -1106,7 +1096,10 @@ export const Group = ({
rej(response.error);
})
.catch((error) => {
rej(error.message || 'An error occurred');
rej(
error.message ||
t('core:message.error.generic', { postProcess: 'capitalize' })
);
});
});
setInfoSnack({

View File

@ -140,6 +140,7 @@ export const ListOfGroupPromotions = () => {
let data: any[] = [];
const uniqueGroupIds = new Set();
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
const getPromos = responseData?.map(async (promo: any) => {
if (promo?.size < 200 && promo.created > oneWeekAgo) {
const name = await requestQueuePromos.enqueue(async () => {
@ -241,9 +242,12 @@ export const ListOfGroupPromotions = () => {
rej(response.error);
})
.catch((error) => {
rej(error.message || 'An error occurred');
rej(
error.message ||
t('core:message.error.generic', { postProcess: 'capitalize' })
);
});
});
}); // TODO translate
setInfoSnack({
type: 'success',
message:

View File

@ -61,7 +61,7 @@ export const ListOfInvites = ({
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
const [isLoadingCancelInvite, setIsLoadingCancelInvite] = useState(false);
const { t } = useTranslation(['core', 'group']);
const listRef = useRef();
const listRef = useRef(null);
const getInvites = async (groupId) => {
try {
@ -91,7 +91,6 @@ export const ListOfInvites = ({
const handleCancelInvitation = async (address) => {
try {
// TODO translate
const fee = await getFee('CANCEL_GROUP_INVITE');
await show({
@ -101,7 +100,9 @@ export const ListOfInvites = ({
}),
publishFee: fee.fee + ' QORT',
});
setIsLoadingCancelInvite(true);
await new Promise((res, rej) => {
window
.sendMessage('cancelInvitationToGroup', {
@ -112,8 +113,9 @@ export const ListOfInvites = ({
if (!response?.error) {
setInfoSnack({
type: 'success',
message:
'Successfully canceled invitation. It may take a couple of minutes for the changes to propagate',
message: t('group:message.success.invitation_cancellation', {
postProcess: 'capitalize',
}),
});
setOpenSnack(true);
handlePopoverClose();
@ -131,7 +133,11 @@ export const ListOfInvites = ({
.catch((error) => {
setInfoSnack({
type: 'error',
message: error.message || 'An error occurred',
message:
error.message ||
t('core:message.error.generic', {
postProcess: 'capitalize',
}),
});
setOpenSnack(true);
rej(error);
@ -189,7 +195,9 @@ export const ListOfInvites = ({
variant="contained"
onClick={() => handleCancelInvitation(member?.invitee)}
>
Cancel Invitation
{t('core:action.cancel_invitation', {
postProcess: 'capitalize',
})}
</LoadingButton>
</Box>
</Popover>
@ -207,6 +215,7 @@ export const ListOfInvites = ({
}
/>
</ListItemAvatar>
<ListItemText primary={member?.name || member?.invitee} />
</ListItemButton>
</ListItem>
@ -218,7 +227,11 @@ export const ListOfInvites = ({
return (
<div>
<p>Invitees list</p>
<p>
{t('group:invitees_list', {
postProcess: 'capitalize',
})}
</p>
<div
style={{
display: 'flex',

View File

@ -15,11 +15,12 @@ import {
List,
} from 'react-virtualized';
import { getNameInfo } from './Group';
import { getBaseApi, getFee } from '../../background';
import { getFee } from '../../background';
import { LoadingButton } from '@mui/lab';
import { getBaseApiReact } from '../../App';
import { txListAtom } from '../../atoms/global';
import { useAtom } from 'jotai';
import { useTranslation } from 'react-i18next';
export const getMemberInvites = async (groupNumber) => {
const response = await fetch(
@ -59,11 +60,11 @@ export const ListOfJoinRequests = ({
}) => {
const [invites, setInvites] = useState([]);
const [txList, setTxList] = useAtom(txListAtom);
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
const listRef = useRef();
const listRef = useRef(null);
const [isLoadingAccept, setIsLoadingAccept] = useState(false);
const { t } = useTranslation(['core', 'group']);
const getInvites = async (groupId) => {
try {
@ -93,7 +94,8 @@ export const ListOfJoinRequests = ({
const handleAcceptJoinRequest = async (address) => {
try {
const fee = await getFee('GROUP_INVITE'); // TODO translate
const fee = await getFee('GROUP_INVITE');
await show({
message: t('group:question.perform_transaction', {
action: 'GROUP_INVITE',
@ -101,7 +103,9 @@ export const ListOfJoinRequests = ({
}),
publishFee: fee.fee + ' QORT',
});
setIsLoadingAccept(true);
await new Promise((res, rej) => {
window
.sendMessage('inviteToGroup', {
@ -114,19 +118,23 @@ export const ListOfJoinRequests = ({
setIsLoadingAccept(false);
setInfoSnack({
type: 'success',
message:
'Successfully accepted join request. It may take a couple of minutes for the changes to propagate',
message: t('group:message.success,group_join', {
postProcess: 'capitalize',
}),
});
setOpenSnack(true);
handlePopoverClose();
res(response);
setTxList((prev) => [
{
...response,
type: 'join-request-accept',
label: `Accepted join request: awaiting confirmation`,
labelDone: `User successfully joined!`,
label: t('group:message.success,invitation_request', {
postProcess: 'capitalize',
}),
labelDone: t('group:message.success,user_joined', {
postProcess: 'capitalize',
}),
done: false,
groupId,
qortalAddress: address,
@ -147,13 +155,16 @@ export const ListOfJoinRequests = ({
.catch((error) => {
setInfoSnack({
type: 'error',
message: error?.message || 'An error occurred',
message:
error?.message ||
t('core:message.error.generic', { postProcess: 'capitalize' }),
});
setOpenSnack(true);
rej(error);
});
});
} catch (error) {
console.log(error);
} finally {
setIsLoadingAccept(false);
}
@ -161,13 +172,15 @@ export const ListOfJoinRequests = ({
const rowRenderer = ({ index, key, parent, style }) => {
const member = invites[index];
const findJoinRequsetInTxList = txList?.find(
const findJoinRequestInTxList = txList?.find(
(tx) =>
tx?.groupId === groupId &&
tx?.qortalAddress === member?.joiner &&
tx?.type === 'join-request-accept'
);
if (findJoinRequsetInTxList) return null;
if (findJoinRequestInTxList) return null;
return (
<CellMeasurer
key={key}
@ -210,10 +223,11 @@ export const ListOfJoinRequests = ({
variant="contained"
onClick={() => handleAcceptJoinRequest(member?.joiner)}
>
Accept
{t('core:action.accept', { postProcess: 'capitalize' })}
</LoadingButton>
</Box>
</Popover>
<ListItemButton
onClick={(event) => handlePopoverOpen(event, index)}
>
@ -238,7 +252,7 @@ export const ListOfJoinRequests = ({
return (
<div>
<p>Join request list</p>
<p>{t('core:list.join_request', { postProcess: 'capitalize' })}</p>
<div
style={{
position: 'relative',

View File

@ -133,7 +133,10 @@ export const Settings = ({ open, setOpen, rawWallet }) => {
rej(response.error);
})
.catch((error) => {
rej(error.message || 'An error occurred');
rej(
error.message ||
t('core:message.error.generic', { postProcess: 'capitalize' })
);
});
});
} catch (error) {

View File

@ -264,7 +264,7 @@ export const UserListOfInvites = ({
}}
>
<p>
{t('core:invite_list', {
{t('core:list.invite', {
postProcess: 'capitalize',
})}
</p>