Add translations and new items

This commit is contained in:
Nicola Benaglia 2025-05-20 19:43:29 +02:00
parent bd1a7b5a5a
commit 4a71cc3f30
9 changed files with 136 additions and 59 deletions

View File

@ -67,7 +67,7 @@ interface VideoPlayerProps {
user?: string; user?: string;
} }
// TODO translate and theme? Is it worth? // TODO translate and theme (optional)
export const VideoPlayer: FC<VideoPlayerProps> = ({ export const VideoPlayer: FC<VideoPlayerProps> = ({
poster, poster,
name, name,

View File

@ -1,4 +1,4 @@
import * as React from 'react'; import { useEffect, useMemo, useState } from 'react';
import List from '@mui/material/List'; import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem'; import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton'; import ListItemButton from '@mui/material/ListItemButton';
@ -27,12 +27,10 @@ export const GroupJoinRequests = ({
setMobileViewMode, setMobileViewMode,
setDesktopViewMode, setDesktopViewMode,
}) => { }) => {
const [isExpanded, setIsExpanded] = React.useState(false); const [isExpanded, setIsExpanded] = useState(false);
const { t } = useTranslation(['auth', 'core', 'group']); const { t } = useTranslation(['auth', 'core', 'group']);
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = React.useState( const [groupsWithJoinRequests, setGroupsWithJoinRequests] = useState([]);
[] const [loading, setLoading] = useState(true);
);
const [loading, setLoading] = React.useState(true);
const [txList] = useAtom(txListAtom); const [txList] = useAtom(txListAtom);
const setMyGroupsWhereIAmAdmin = useSetAtom(myGroupsWhereIAmAdminAtom); const setMyGroupsWhereIAmAdmin = useSetAtom(myGroupsWhereIAmAdminAtom);
@ -91,7 +89,7 @@ export const GroupJoinRequests = ({
} }
}; };
React.useEffect(() => { useEffect(() => {
if (myAddress && groups.length > 0) { if (myAddress && groups.length > 0) {
getJoinRequests(); getJoinRequests();
} else { } else {
@ -99,7 +97,7 @@ export const GroupJoinRequests = ({
} }
}, [myAddress, groups]); }, [myAddress, groups]);
const filteredJoinRequests = React.useMemo(() => { const filteredJoinRequests = useMemo(() => {
return groupsWithJoinRequests.map((group) => { return groupsWithJoinRequests.map((group) => {
const filteredGroupRequests = group?.data?.filter((gd) => { const filteredGroupRequests = group?.data?.filter((gd) => {
const findJoinRequsetInTxList = txList?.find( const findJoinRequsetInTxList = txList?.find(
@ -271,8 +269,15 @@ export const GroupJoinRequests = ({
fontSize: '13px', fontSize: '13px',
fontWeight: 400, fontWeight: 400,
}, },
}} // TODO translate }}
primary={`${group?.group?.groupName} has ${group?.data?.length} pending join requests.`} primary={t(
'group:message.generic.pending_join_requests',
{
group: group?.group?.groupName,
count: group?.data?.length,
postProcess: 'capitalizeFirstChar',
}
)}
/> />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>

View File

@ -174,8 +174,11 @@ export const ListOfThreadPostsWatched = () => {
} }
> >
<ListItemButton disableRipple role={undefined} dense> <ListItemButton disableRipple role={undefined} dense>
<ListItemText //TODO translate <ListItemText
primary={`New post in ${post?.thread?.threadData?.title}`} primary={t('core:new_post_in', {
title: post?.thread?.threadData?.title,
postProcess: 'capitalizeFirstChar',
})}
/> />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>

View File

@ -1,15 +1,7 @@
import { Box, CircularProgress, useTheme } from '@mui/material'; import { Box, useTheme } from '@mui/material';
import { useState } from 'react'; import { useState } from 'react';
import { import { TextP } from '../styles/App-styles';
CustomButton,
CustomInput,
CustomLabel,
TextP,
} from '../styles/App-styles';
import { Spacer } from '../common/Spacer'; import { Spacer } from '../common/Spacer';
import BoundedNumericTextField from '../common/BoundedNumericTextField';
import { PasswordField } from './PasswordField/PasswordField';
import { ErrorText } from './ErrorText/ErrorText';
import { getFee } from '../background'; import { getFee } from '../background';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -28,22 +20,37 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
setSendPaymentError(''); setSendPaymentError('');
setSendPaymentSuccess(''); setSendPaymentSuccess('');
if (!paymentTo) { if (!paymentTo) {
setSendPaymentError('Please enter a recipient'); setSendPaymentError(
t('auth:action.enter_recipient', {
postProcess: 'capitalizeFirstChar',
})
);
return; return;
} }
if (!paymentAmount) { if (!paymentAmount) {
setSendPaymentError('Please enter an amount greater than 0'); setSendPaymentError(
t('auth:action.enter_amount', {
postProcess: 'capitalizeFirstChar',
})
);
return; return;
} }
if (!paymentPassword) { if (!paymentPassword) {
setSendPaymentError('Please enter your wallet password'); setSendPaymentError(
t('auth:action.enter_wallet_password', {
postProcess: 'capitalizeFirstChar',
})
);
return; return;
} }
const fee = await getFee('PAYMENT'); // TODO translate const fee = await getFee('PAYMENT');
await show({ await show({
message: `Would you like to transfer ${Number(paymentAmount)} QORT?`, message: t('core:message.question.transfer_qort', {
amount: Number(paymentAmount),
postProcess: 'capitalizeFirstChar',
}),
paymentFee: fee.fee + ' QORT', paymentFee: fee.fee + ' QORT',
}); });
@ -89,7 +96,9 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
textAlign: 'start', textAlign: 'start',
}} }}
> >
Transfer QORT {t('core:action.transfer_qort', {
postProcess: 'capitalizeFirstChar',
})}
</TextP> </TextP>
<Spacer height="35px" /> <Spacer height="35px" />
@ -103,7 +112,9 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
textAlign: 'start', textAlign: 'start',
}} }}
> >
Balance: {t('core:balance', {
postProcess: 'capitalizeFirstChar',
})}
</TextP> </TextP>
<TextP <TextP
@ -121,7 +132,11 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
<Spacer height="35px" /> <Spacer height="35px" />
<Box> <Box>
<CustomLabel htmlFor="standard-adornment-name">To</CustomLabel> <CustomLabel htmlFor="standard-adornment-name">
{t('core:to', {
postProcess: 'capitalizeFirstChar',
})}
</CustomLabel>
<Spacer height="5px" /> <Spacer height="5px" />
@ -134,7 +149,11 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
<Spacer height="6px" /> <Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-amount">Amount</CustomLabel> <CustomLabel htmlFor="standard-adornment-amount">
{t('core:amount', {
postProcess: 'capitalizeFirstChar',
})}
</CustomLabel>
<Spacer height="5px" /> <Spacer height="5px" />
@ -151,7 +170,9 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
<Spacer height="6px" /> <Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-password"> <CustomLabel htmlFor="standard-adornment-password">
Confirm wallet password {t('auth:wallet.password_confirmation', {
postProcess: 'capitalizeFirstChar',
})}
</CustomLabel> </CustomLabel>
<Spacer height="5px" /> <Spacer height="5px" />
@ -173,7 +194,6 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
<Spacer height="10px" /> <Spacer height="10px" />
<ErrorText>{sendPaymentError}</ErrorText> <ErrorText>{sendPaymentError}</ErrorText>
{/* <Typography>{sendPaymentSuccess}</Typography> */}
<Spacer height="25px" /> <Spacer height="25px" />
@ -194,7 +214,7 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
}} }}
/> />
)} )}
Send {t('core:action.send', { postProcess: 'capitalizeFirstChar' })}
</CustomButton> </CustomButton>
</> </>
); );

View File

@ -30,14 +30,20 @@ export const useHandlePrivateApps = () => {
setLoadingStatePrivateApp setLoadingStatePrivateApp
) => { ) => {
try { try {
if (setLoadingStatePrivateApp) { // TODO translate if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp(`Downloading and decrypting private app.`); setLoadingStatePrivateApp(
t('core:message.generic.downloading_decrypting_app', {
postProcess: 'capitalizeFirstChar',
})
);
} }
setOpenSnackGlobal(true); setOpenSnackGlobal(true);
setInfoSnackCustom({ setInfoSnackCustom({
type: 'info', type: 'info',
message: 'Fetching app data', message: t('core:message.generic.fetching_data', {
postProcess: 'capitalizeFirstChar',
}),
duration: null, duration: null,
}); });
const urlData = `${getBaseApiReact()}/arbitrary/${ const urlData = `${getBaseApiReact()}/arbitrary/${
@ -56,7 +62,11 @@ export const useHandlePrivateApps = () => {
if (!responseData?.ok) { if (!responseData?.ok) {
if (setLoadingStatePrivateApp) { if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to download private app.'); setLoadingStatePrivateApp(
t('core:message.generic.unable_download_private_app', {
postProcess: 'capitalizeFirstChar',
})
);
} }
throw new Error('Unable to fetch app'); throw new Error('Unable to fetch app');
@ -65,13 +75,25 @@ export const useHandlePrivateApps = () => {
data = await responseData.text(); data = await responseData.text();
if (data?.error) { if (data?.error) {
if (setLoadingStatePrivateApp) { if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to download private app.'); setLoadingStatePrivateApp(
t('core:message.generic.unable_download_private_app', {
postProcess: 'capitalizeFirstChar',
})
);
} }
throw new Error('Unable to fetch app'); throw new Error(
t('core:message.generic.unable_fetch_app', {
postProcess: 'capitalizeFirstChar',
})
);
} }
} catch (error) { } catch (error) {
if (setLoadingStatePrivateApp) { if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to download private app.'); setLoadingStatePrivateApp(
t('core:message.generic.unable_download_private_app', {
postProcess: 'capitalizeFirstChar',
})
);
} }
throw error; throw error;
} }
@ -79,23 +101,27 @@ export const useHandlePrivateApps = () => {
let decryptedData; let decryptedData;
// eslint-disable-next-line no-useless-catch // eslint-disable-next-line no-useless-catch
try { try {
decryptedData = await window.sendMessage( decryptedData = await window.sendMessage('DECRYPT_QORTAL_GROUP_DATA', {
'DECRYPT_QORTAL_GROUP_DATA', base64: data,
groupId: privateAppProperties?.groupId,
{ });
base64: data,
groupId: privateAppProperties?.groupId,
}
);
if (decryptedData?.error) { if (decryptedData?.error) {
if (setLoadingStatePrivateApp) { if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to decrypt private app.'); setLoadingStatePrivateApp(
t('core:message.generic.unable_decrypt_app', {
postProcess: 'capitalizeFirstChar',
})
);
} }
throw new Error(decryptedData?.error); throw new Error(decryptedData?.error);
} }
} catch (error) { } catch (error) {
if (setLoadingStatePrivateApp) { if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to decrypt private app.'); setLoadingStatePrivateApp(
t('core:message.generic.unable_decrypt_app', {
postProcess: 'capitalizeFirstChar',
})
);
} }
throw error; throw error;
} }
@ -107,11 +133,15 @@ export const useHandlePrivateApps = () => {
if (decryptedData) { if (decryptedData) {
setInfoSnackCustom({ setInfoSnackCustom({
type: 'info', type: 'info',
message: 'Building app', message: t('core:message.generic.building_app', {
postProcess: 'capitalizeFirstChar',
}),
}); });
const endpoint = await createEndpoint( const endpoint = await createEndpoint(
`/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true` `/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true`
); );
const response = await fetch(endpoint, { const response = await fetch(endpoint, {
method: 'POST', method: 'POST',
headers: { headers: {
@ -119,7 +149,9 @@ export const useHandlePrivateApps = () => {
}, },
body: UintToObject?.app, body: UintToObject?.app,
}); });
const previewPath = await response.text(); const previewPath = await response.text();
const refreshfunc = async (tabId, privateAppProperties) => { const refreshfunc = async (tabId, privateAppProperties) => {
const checkIfPreviewLinkStillWorksUrl = await createEndpoint( const checkIfPreviewLinkStillWorksUrl = await createEndpoint(
`/render/hash/HmtnZpcRPwisMfprUXuBp27N2xtv5cDiQjqGZo8tbZS?secret=E39WTiG4qBq3MFcMPeRZabtQuzyfHg9ZuR5SgY7nW1YH` `/render/hash/HmtnZpcRPwisMfprUXuBp27N2xtv5cDiQjqGZo8tbZS?secret=E39WTiG4qBq3MFcMPeRZabtQuzyfHg9ZuR5SgY7nW1YH`
@ -133,6 +165,7 @@ export const useHandlePrivateApps = () => {
const endpoint = await createEndpoint( const endpoint = await createEndpoint(
`/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true` `/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true`
); );
const response = await fetch(endpoint, { const response = await fetch(endpoint, {
method: 'POST', method: 'POST',
headers: { headers: {
@ -140,6 +173,7 @@ export const useHandlePrivateApps = () => {
}, },
body: UintToObject?.app, body: UintToObject?.app,
}); });
const previewPath = await response.text(); const previewPath = await response.text();
executeEvent('updateAppUrl', { executeEvent('updateAppUrl', {
tabId: tabId, tabId: tabId,
@ -174,7 +208,9 @@ export const useHandlePrivateApps = () => {
}); });
setInfoSnackCustom({ setInfoSnackCustom({
type: 'success', type: 'success',
message: {t('core:message.generic.opened', { postProcess: 'capitalizeFirstChar' })}, message: t('core:message.generic.opened', {
postProcess: 'capitalizeFirstChar',
}),
}); });
if (setLoadingStatePrivateApp) { if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp(``); setLoadingStatePrivateApp(``);

View File

@ -165,7 +165,7 @@ export function openIndexedDB() {
reject('Error opening IndexedDB'); reject('Error opening IndexedDB');
}; };
}); });
} // TODO translate }
export const listOfAllQortalRequests = [ export const listOfAllQortalRequests = [
'ADD_FOREIGN_SERVER', 'ADD_FOREIGN_SERVER',
@ -658,7 +658,7 @@ export const useQortalMessageListener = (
setPath(pathUrl); setPath(pathUrl);
if (appName?.toLowerCase() === 'q-mail') { if (appName?.toLowerCase() === 'q-mail') {
window.sendMessage('addEnteredQmailTimestamp').catch((error) => { window.sendMessage('addEnteredQmailTimestamp').catch((error) => {
// error // TODO print error
}); });
} else if (appName?.toLowerCase() === 'q-wallets') { } else if (appName?.toLowerCase() === 'q-wallets') {
executeEvent('setLastEnteredTimestampPaymentEvent', {}); executeEvent('setLastEnteredTimestampPaymentEvent', {});

View File

@ -22,6 +22,9 @@
"create_qortal_account": "create your Qortal account by clicking <next>NEXT</next> below.", "create_qortal_account": "create your Qortal account by clicking <next>NEXT</next> below.",
"choose_password": "choose new password", "choose_password": "choose new password",
"download_account": "download account", "download_account": "download account",
"enter_amount": "please enter an amount greater than 0",
"enter_recipient": "please enter a recipient",
"enter_wallet_password": "please enter your wallet password",
"export_seedphrase": "export Seedphrase", "export_seedphrase": "export Seedphrase",
"insert_name_address": "please insert a name or address", "insert_name_address": "please insert a name or address",
"publish_admin_secret_key": "publish admin secret key", "publish_admin_secret_key": "publish admin secret key",

View File

@ -70,6 +70,7 @@
"select_app_type": "select App Type", "select_app_type": "select App Type",
"select_category": "select Category", "select_category": "select Category",
"select_name_app": "select Name/App", "select_name_app": "select Name/App",
"send": "send",
"send_qort": "send QORT", "send_qort": "send QORT",
"set_avatar": "set avatar", "set_avatar": "set avatar",
"show": "show", "show": "show",
@ -98,7 +99,7 @@
"apps_dashboard": "apps Dashboard", "apps_dashboard": "apps Dashboard",
"apps_official": "official Apps", "apps_official": "official Apps",
"attachment": "attachment", "attachment": "attachment",
"balance": "balance", "balance": "balance:",
"category": "category", "category": "category",
"category_other": "categories", "category_other": "categories",
"chat": "chat", "chat": "chat",
@ -174,8 +175,10 @@
"send_failed": "failed to send", "send_failed": "failed to send",
"unable_build_app": "unable to build private app", "unable_build_app": "unable to build private app",
"unable_download_image": "unable to download IMAGE. Please try again later by clicking the refresh button", "unable_download_image": "unable to download IMAGE. Please try again later by clicking the refresh button",
"unable_download_private_app": "unable to download private app",
"unable_decrypt_app": "unable to decrypt private app'",
"unable_encrypt_app": "unable to encrypt app. App not published'", "unable_encrypt_app": "unable to encrypt app. App not published'",
"unable_fetch_app": "unable to build private app", "unable_fetch_app": "unable to fetch app",
"unable_publish_app": "unable to publish app", "unable_publish_app": "unable to publish app",
"unable_publish_image": "unable to publish image", "unable_publish_image": "unable to publish image",
"unable_rate": "unable to rate", "unable_rate": "unable to rate",
@ -186,16 +189,19 @@
"already_voted": "you've already voted.", "already_voted": "you've already voted.",
"avatar_size": "{{ size }} KB max. for GIFS", "avatar_size": "{{ size }} KB max. for GIFS",
"building": "building", "building": "building",
"building_app": "building app",
"created_by": "created by {{ owner }}", "created_by": "created by {{ owner }}",
"buy_order_request": "the Application <br/><italic>{{hostname}}</italic> <br/><span>is requesting {{count}} buy order</span>", "buy_order_request": "the Application <br/><italic>{{hostname}}</italic> <br/><span>is requesting {{count}} buy order</span>",
"buy_order_request_other": "the Application <br/><italic>{{hostname}}</italic> <br/><span>is requesting {{count}} buy orders</span>", "buy_order_request_other": "the Application <br/><italic>{{hostname}}</italic> <br/><span>is requesting {{count}} buy orders</span>",
"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.",
"downloading": "downloading", "downloading": "downloading",
"downloading_decrypting_app": "downloading and decrypting private app.",
"edited": "edited", "edited": "edited",
"editing_message": "editing message", "editing_message": "editing message",
"encrypted": "encrypted", "encrypted": "encrypted",
"encrypted_not": "not encrypted", "encrypted_not": "not encrypted",
"fee_qort": "fee: {{ message }} QORT", "fee_qort": "fee: {{ message }} QORT",
"fetching_data": "fetching app data",
"foreign_fee": "foreign fee: {{ message }}", "foreign_fee": "foreign fee: {{ message }}",
"mentioned": "mentioned", "mentioned": "mentioned",
"message_with_image": "this message already has an image", "message_with_image": "this message already has an image",
@ -259,7 +265,8 @@
"rate_app": "would you like to rate this app a rating of {{ rate }}?. It will create a POLL tx.", "rate_app": "would you like to rate this app a rating of {{ rate }}?. It will create a POLL tx.",
"register_name": "would you like to register this name?", "register_name": "would you like to register this name?",
"reset_pinned": "don't like your current local changes? Would you like to reset to the default pinned apps?", "reset_pinned": "don't like your current local changes? Would you like to reset to the default pinned apps?",
"reset_qdn": "don't like your current local changes? Would you like to reset to your saved QDN pinned apps?" "reset_qdn": "don't like your current local changes? Would you like to reset to your saved QDN pinned apps?",
"transfer_qort": "would you like to transfer {{ amount }} QORT"
}, },
"status": { "status": {
"minting": "(minting)", "minting": "(minting)",
@ -280,6 +287,7 @@
"minting_status": "minting status", "minting_status": "minting status",
"name": "name", "name": "name",
"name_app": "name/App", "name_app": "name/App",
"new_post_in": "new post in {{ title }}",
"none": "none", "none": "none",
"option": "option", "option": "option",
"option_other": "options", "option_other": "options",
@ -325,6 +333,7 @@
"time": "time" "time": "time"
}, },
"title": "title", "title": "title",
"to": "to",
"tutorial": "tutorial", "tutorial": "tutorial",
"user_lookup": "user lookup", "user_lookup": "user lookup",
"vote": "vote", "vote": "vote",

View File

@ -99,6 +99,7 @@
"not_part_group": "you are not part of the encrypted group of members. Wait until an admin re-encrypts the keys.", "not_part_group": "you are not part of the encrypted group of members. Wait until an admin re-encrypts the keys.",
"only_encrypted": "only unencrypted messages will be displayed.", "only_encrypted": "only unencrypted messages will be displayed.",
"only_private_groups": "only private groups will be shown", "only_private_groups": "only private groups will be shown",
"pending_join_requests": "{{ group }} has {{ count }} pending join requests",
"private_key_copied": "private key copied", "private_key_copied": "private key copied",
"provide_message": "please provide a first message to the thread", "provide_message": "please provide a first message to the thread",
"secure_place": "keep your private key in a secure place. Do not share!", "secure_place": "keep your private key in a secure place. Do not share!",