Add translations

This commit is contained in:
Nicola Benaglia 2025-05-17 09:45:36 +02:00
parent 7684201ba9
commit 8c4b5d27ed
5 changed files with 108 additions and 55 deletions

View File

@ -827,23 +827,33 @@ export const ChatGroup = ({
if (replyMessage?.chatReference) { if (replyMessage?.chatReference) {
repliedTo = replyMessage?.chatReference; repliedTo = replyMessage?.chatReference;
} }
let chatReference = onEditMessage?.signature;
const chatReference = onEditMessage?.signature;
const publicData = isPrivate const publicData = isPrivate
? {} ? {}
: { : {
isEdited: chatReference ? true : false, isEdited: chatReference ? true : false,
}; };
const imagesToPublish = [];
interface ImageToPublish {
service: string;
identifier: string;
name: string;
base64: string;
}
const imagesToPublish: ImageToPublish[] = [];
const deleteImage = const deleteImage =
onEditMessage && isDeleteImage && messageHasImage(onEditMessage); onEditMessage && isDeleteImage && messageHasImage(onEditMessage);
if (deleteImage) { if (deleteImage) {
const fee = await getFee('ARBITRARY'); const fee = await getFee('ARBITRARY');
// TODO translate
await show({ await show({
publishFee: fee.fee + ' QORT', publishFee: fee.fee + ' QORT',
message: 'Would you like to delete your previous chat image?', message: t('core:question.delete_chat_image', {
postProcess: 'capitalizeFirst',
}),
}); });
// TODO magic string // TODO magic string
@ -853,6 +863,7 @@ export const ChatGroup = ({
service: onEditMessage?.images[0]?.service, service: onEditMessage?.images[0]?.service,
}); });
} }
if (chatImagesToSave?.length > 0) { if (chatImagesToSave?.length > 0) {
const imageToSave = chatImagesToSave[0]; const imageToSave = chatImagesToSave[0];
@ -877,7 +888,12 @@ export const ChatGroup = ({
240000, 240000,
true true
); );
if (res !== true) throw new Error('Unable to publish images'); if (res !== true)
throw new Error(
t('core:message.error.unable_publish_image', {
postProcess: 'capitalizeFirst',
})
);
} }
const images = const images =
@ -916,7 +932,6 @@ export const ChatGroup = ({
isPrivate === false isPrivate === false
? JSON.stringify(objectMessage) ? JSON.stringify(objectMessage)
: await encryptChatMessage(message64, secretKeyObject); : await encryptChatMessage(message64, secretKeyObject);
// const res = await sendChatGroup({groupId: selectedGroup,messageText: encryptSingle})
const sendMessageFunc = async () => { const sendMessageFunc = async () => {
return await sendChatGroup({ return await sendChatGroup({
@ -1033,13 +1048,19 @@ export const ChatGroup = ({
try { try {
if (isSending) return; if (isSending) return;
if (+balance < 4) if (+balance < 4)
throw new Error('You need at least 4 QORT to send a message'); // TODO magic number
pauseAllQueues(); throw new Error(
t('group:message.error.qortals_required', {
quantity: 4,
postProcess: 'capitalizeFirst',
})
);
pauseAllQueues();
setIsSending(true); setIsSending(true);
const message = ''; const message = '';
const secretKeyObject = await getSecretKey(false, true); const secretKeyObject = await getSecretKey(false, true);
const otherData = { const otherData = {
specialId: uid.rnd(), specialId: uid.rnd(),
type: 'reaction', type: 'reaction',
@ -1060,8 +1081,6 @@ export const ChatGroup = ({
secretKeyObject, secretKeyObject,
reactiontypeNumber reactiontypeNumber
); );
// const res = await sendChatGroup({groupId: selectedGroup,messageText: encryptSingle})
const sendMessageFunc = async () => { const sendMessageFunc = async () => {
return await sendChatGroup({ return await sendChatGroup({
groupId: selectedGroup, groupId: selectedGroup,
@ -1113,7 +1132,9 @@ export const ChatGroup = ({
) { ) {
setInfoSnack({ setInfoSnack({
type: 'error', type: 'error',
message: 'This message already has an image', message: t('core:message.generic.message_with_image', {
postProcess: 'capitalizeFirst',
}),
}); });
setOpenSnack(true); setOpenSnack(true);
return; return;
@ -1122,6 +1143,7 @@ export const ChatGroup = ({
}, },
[chatImagesToSave, onEditMessage?.images, isDeleteImage] [chatImagesToSave, onEditMessage?.images, isDeleteImage]
); );
return ( return (
<div <div
style={{ style={{
@ -1130,34 +1152,36 @@ export const ChatGroup = ({
height: '100%', height: '100%',
left: hide && '-100000px', left: hide && '-100000px',
opacity: hide ? 0 : 1, opacity: hide ? 0 : 1,
padding: '10px',
position: hide ? 'absolute' : 'relative', position: hide ? 'absolute' : 'relative',
width: '100%', width: '100%',
padding: '10px',
}} }}
> >
<ChatList <ChatList
isPrivate={isPrivate}
hasSecretKey={!!secretKey}
openQManager={openQManager}
enableMentions
onReply={onReply}
onEdit={onEdit}
chatId={selectedGroup} chatId={selectedGroup}
initialMessages={messages}
myAddress={myAddress}
tempMessages={tempMessages}
handleReaction={handleReaction}
chatReferences={chatReferences} chatReferences={chatReferences}
tempChatReferences={tempChatReferences} enableMentions
handleReaction={handleReaction}
hasSecretKey={!!secretKey}
initialMessages={messages}
isPrivate={isPrivate}
members={members} members={members}
myAddress={myAddress}
myName={myName} myName={myName}
onEdit={onEdit}
onReply={onReply}
openQManager={openQManager}
selectedGroup={selectedGroup} selectedGroup={selectedGroup}
tempChatReferences={tempChatReferences}
tempMessages={tempMessages}
/> />
{(!!secretKey || isPrivate === false) && ( {(!!secretKey || isPrivate === false) && (
<div <div
style={{ style={{
backgroundColor: theme.palette.background.surface, backgroundColor: theme.palette.background.surface,
border: `1px solid ${theme.palette.border.subtle}`,
borderRadius: '10px',
bottom: isFocusedParent ? '0px' : 'unset', bottom: isFocusedParent ? '0px' : 'unset',
boxSizing: 'border-box', boxSizing: 'border-box',
display: 'flex', display: 'flex',
@ -1170,8 +1194,6 @@ export const ChatGroup = ({
top: isFocusedParent ? '0px' : 'unset', top: isFocusedParent ? '0px' : 'unset',
width: '100%', width: '100%',
zIndex: isFocusedParent ? 5 : 'unset', zIndex: isFocusedParent ? 5 : 'unset',
border: `1px solid ${theme.palette.border.subtle}`,
borderRadius: '10px',
}} }}
> >
<div <div
@ -1189,9 +1211,9 @@ export const ChatGroup = ({
sx={{ sx={{
alignItems: 'flex-start', alignItems: 'flex-start',
display: 'flex', display: 'flex',
width: '100%',
gap: '10px',
flexWrap: 'wrap', flexWrap: 'wrap',
gap: '10px',
width: '100%',
}} }}
> >
{!isDeleteImage && {!isDeleteImage &&
@ -1201,19 +1223,20 @@ export const ChatGroup = ({
<div <div
key={index} key={index}
style={{ style={{
position: 'relative',
height: '50px', height: '50px',
position: 'relative',
width: '50px', width: '50px',
}} }}
> >
<ImageIcon <ImageIcon
color="primary" color="primary"
sx={{ sx={{
borderRadius: '3px',
height: '100%', height: '100%',
width: '100%', width: '100%',
borderRadius: '3px',
}} }}
/> />
<Tooltip title="Delete image"> <Tooltip title="Delete image">
<IconButton <IconButton
onClick={() => setIsDeleteImage(true)} onClick={() => setIsDeleteImage(true)}
@ -1243,12 +1266,13 @@ export const ChatGroup = ({
</Tooltip> </Tooltip>
</div> </div>
))} ))}
{chatImagesToSave.map((imgBase64, index) => ( {chatImagesToSave.map((imgBase64, index) => (
<div <div
key={index} key={index}
style={{ style={{
position: 'relative',
height: '50px', height: '50px',
position: 'relative',
width: '50px', width: '50px',
}} }}
> >
@ -1261,6 +1285,7 @@ export const ChatGroup = ({
borderRadius: '3px', borderRadius: '3px',
}} }}
/> />
<Tooltip title="Remove image"> <Tooltip title="Remove image">
<IconButton <IconButton
onClick={() => onClick={() =>
@ -1295,6 +1320,7 @@ export const ChatGroup = ({
</div> </div>
))} ))}
</Box> </Box>
{replyMessage && ( {replyMessage && (
<Box <Box
sx={{ sx={{
@ -1319,6 +1345,7 @@ export const ChatGroup = ({
</ButtonBase> </ButtonBase>
</Box> </Box>
)} )}
{onEditMessage && ( {onEditMessage && (
<Box <Box
sx={{ sx={{
@ -1364,13 +1391,19 @@ export const ChatGroup = ({
width: '100%', width: '100%',
}} }}
> >
<Typography <Typography //TODO magic number
sx={{ sx={{
fontSize: '12px', fontSize: '12px',
color: color:
messageSize > 4000 ? theme.palette.other.danger : 'unset', messageSize > 4000 ? theme.palette.other.danger : 'unset',
}} }}
>{`Your message size is of ${messageSize} bytes out of a maximum of 4000`}</Typography> >
{t('core:message.error.message_size', {
maximum: 4000,
size: messageSize,
postProcess: 'capitalizeFirst',
})}
</Typography>
</Box> </Box>
)} )}
</div> </div>
@ -1421,6 +1454,7 @@ export const ChatGroup = ({
</Box> </Box>
</div> </div>
)} )}
{isOpenQManager !== null && ( {isOpenQManager !== null && (
<Box <Box
sx={{ sx={{
@ -1479,10 +1513,10 @@ export const ChatGroup = ({
<AppViewerContainer <AppViewerContainer
customHeight="560px" customHeight="560px"
app={{ app={{
tabId: '5558588',
name: 'Q-Manager', name: 'Q-Manager',
service: 'APP',
path: `?groupId=${selectedGroup}`, path: `?groupId=${selectedGroup}`,
service: 'APP',
tabId: '5558588',
}} }}
isSelected isSelected
/> />
@ -1493,7 +1527,7 @@ export const ChatGroup = ({
<LoadingSnackbar <LoadingSnackbar
open={isLoading} open={isLoading}
info={{ info={{
message: 'Loading chat... please wait.', message: t('core:loading.chat', { postProcess: 'capitalizeFirst' }),
}} }}
/> />

View File

@ -5,6 +5,7 @@ import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
import { Box, Button, Typography, useTheme } from '@mui/material'; import { Box, Button, Typography, useTheme } from '@mui/material';
import { ChatOptions } from './ChatOptions'; import { ChatOptions } from './ChatOptions';
import ErrorBoundary from '../../common/ErrorBoundary'; import ErrorBoundary from '../../common/ErrorBoundary';
import { useTranslation } from 'react-i18next';
export const ChatList = ({ export const ChatList = ({
initialMessages, initialMessages,
@ -180,6 +181,7 @@ export const ChatList = ({
}, []); }, []);
const theme = useTheme(); const theme = useTheme();
const { t } = useTranslation(['auth', 'core', 'group']);
return ( return (
<Box <Box
@ -324,19 +326,23 @@ export const ChatList = ({
<div <div
key={virtualRow.index} key={virtualRow.index}
style={{ style={{
position: 'absolute',
top: 0,
left: '50%',
transform: `translateY(${virtualRow.start}px) translateX(-50%)`,
width: '100%',
padding: '10px 0',
display: 'flex',
alignItems: 'center', alignItems: 'center',
display: 'flex',
flexDirection: 'column', flexDirection: 'column',
gap: '5px', gap: '5px',
left: '50%',
padding: '10px 0',
position: 'absolute',
top: 0,
transform: `translateY(${virtualRow.start}px) translateX(-50%)`,
width: '100%',
}} }}
> >
<Typography>Error loading message.</Typography> <Typography>
{t('core:message.error.message_loading', {
postProcess: 'capitalizeFirst',
})}
</Typography>
</div> </div>
); );
} }
@ -363,26 +369,28 @@ export const ChatList = ({
<ErrorBoundary <ErrorBoundary
fallback={ fallback={
<Typography> <Typography>
Error loading content: Invalid Data {t('group.message.generic.invalid_data', {
postProcess: 'capitalizeFirst',
})}
</Typography> </Typography>
} }
> >
<MessageItem <MessageItem
handleReaction={handleReaction}
isLast={index === messages.length - 1} isLast={index === messages.length - 1}
isPrivate={isPrivate}
isTemp={!!message?.isTemp}
isUpdating={isUpdating}
lastSignature={lastSignature} lastSignature={lastSignature}
message={message} message={message}
onSeen={handleMessageSeen}
isTemp={!!message?.isTemp}
myAddress={myAddress} myAddress={myAddress}
onReply={onReply}
onEdit={onEdit} onEdit={onEdit}
onReply={onReply}
onSeen={handleMessageSeen}
reactions={reactions}
reply={reply} reply={reply}
replyIndex={replyIndex} replyIndex={replyIndex}
scrollToItem={goToMessage} scrollToItem={goToMessage}
handleReaction={handleReaction}
reactions={reactions}
isUpdating={isUpdating}
isPrivate={isPrivate}
/> />
</ErrorBoundary> </ErrorBoundary>
</div> </div>
@ -409,9 +417,12 @@ export const ChatList = ({
zIndex: 10, zIndex: 10,
}} }}
> >
Scroll to Unread Messages {t('group:action.scroll_unread_messages', {
postProcess: 'capitalizeFirst',
})}
</button> </button>
)} )}
{showScrollDownButton && !showScrollButton && ( {showScrollDownButton && !showScrollButton && (
<Button <Button
onClick={() => scrollToBottom()} onClick={() => scrollToBottom()}
@ -432,7 +443,9 @@ export const ChatList = ({
textTransform: 'none', textTransform: 'none',
}} }}
> >
Scroll to bottom {t('group:action.scroll_unread_messages', {
postProcess: 'capitalizeFirst',
})}
</Button> </Button>
)} )}
</div> </div>

View File

@ -125,6 +125,7 @@
"generic": "an error occurred", "generic": "an error occurred",
"invalid_signature": "invalid signature", "invalid_signature": "invalid signature",
"invalid_zip": "invalid zip", "invalid_zip": "invalid zip",
"message_loading": "error loading message.",
"message_size": "your message size is of {{ size }} bytes out of a maximum of {{ maximum }}", "message_size": "your message size is of {{ size }} bytes out of a maximum of {{ maximum }}",
"minting_account_add": "unable to add minting account", "minting_account_add": "unable to add minting account",
"minting_account_remove": "unable to remove minting account", "minting_account_remove": "unable to remove minting account",
@ -138,6 +139,7 @@
"save_qdn": "unable to save to QDN", "save_qdn": "unable to save to QDN",
"unable_encrypt_app": "unable to encrypt app. App not published'", "unable_encrypt_app": "unable to encrypt app. App not published'",
"unable_publish_app": "unable to publish app", "unable_publish_app": "unable to publish app",
"unable_publish_image": "unable to publish image",
"unable_rate": "unable to rate" "unable_rate": "unable to rate"
}, },
"generic": { "generic": {
@ -146,6 +148,7 @@
"devmode_local_node": "please use your local node for dev mode! Logout and use Local node.", "devmode_local_node": "please use your local node for dev mode! Logout and use Local node.",
"fee_qort": "fee: {{ message }} QORT", "fee_qort": "fee: {{ message }} QORT",
"foreign_fee": "foreign fee: {{ message }}", "foreign_fee": "foreign fee: {{ message }}",
"message_with_image": "this message already has an image",
"name_available": "{{ name }} is available", "name_available": "{{ name }} is available",
"name_benefits": "benefits of a name", "name_benefits": "benefits of a name",
"name_checking": "checking if name already exists", "name_checking": "checking if name already exists",
@ -218,6 +221,7 @@
"q_sandbox": "q-Sandbox" "q_sandbox": "q-Sandbox"
}, },
"question": { "question": {
"delete_chat_image": "would you like to delete your previous chat image?",
"perform_transaction": "would you like to perform a {{action}} transaction?", "perform_transaction": "would you like to perform a {{action}} transaction?",
"provide_thread": "please provide a thread title", "provide_thread": "please provide a thread title",
"publish_app": "would you like to publish this app?", "publish_app": "would you like to publish this app?",

View File

@ -22,6 +22,8 @@
"remove_admin": "remove as admin", "remove_admin": "remove as admin",
"remove_minting_account": "remove minting account", "remove_minting_account": "remove minting account",
"return_to_thread": "return to threads", "return_to_thread": "return to threads",
"scroll_bottom": "scroll to bottom",
"scroll_unread_messages": "scroll to Unread Messages",
"select_group": "select a group", "select_group": "select a group",
"visit_q_mintership": "visit Q-Mintership" "visit_q_mintership": "visit Q-Mintership"
}, },

View File

@ -85,7 +85,7 @@ import { RequestQueueWithPromise } from '../utils/queue/queue';
import utils from '../utils/utils'; import utils from '../utils/utils';
import ShortUniqueId from 'short-unique-id'; import ShortUniqueId from 'short-unique-id';
import { isValidBase64WithDecode } from '../utils/decode'; import { isValidBase64WithDecode } from '../utils/decode';
//TODO translate
const uid = new ShortUniqueId({ length: 6 }); const uid = new ShortUniqueId({ length: 6 });
export const requestQueueGetAtAddresses = new RequestQueueWithPromise(10); export const requestQueueGetAtAddresses = new RequestQueueWithPromise(10);