From 4a71cc3f30110e24e3351d574902ec2df6fd758d Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Tue, 20 May 2025 19:43:29 +0200 Subject: [PATCH] Add translations and new items --- src/components/Embeds/VideoPlayer.tsx | 2 +- src/components/Group/GroupJoinRequests.tsx | 25 ++++--- .../Group/ListOfThreadPostsWatched.tsx | 7 +- src/components/QortPayment.tsx | 64 ++++++++++------ src/hooks/useHandlePrivateApps.tsx | 74 ++++++++++++++----- src/hooks/useQortalMessageListener.tsx | 4 +- src/i18n/locales/en/auth.json | 3 + src/i18n/locales/en/core.json | 15 +++- src/i18n/locales/en/group.json | 1 + 9 files changed, 136 insertions(+), 59 deletions(-) diff --git a/src/components/Embeds/VideoPlayer.tsx b/src/components/Embeds/VideoPlayer.tsx index 7bb1272..5bcf181 100644 --- a/src/components/Embeds/VideoPlayer.tsx +++ b/src/components/Embeds/VideoPlayer.tsx @@ -67,7 +67,7 @@ interface VideoPlayerProps { user?: string; } -// TODO translate and theme? Is it worth? +// TODO translate and theme (optional) export const VideoPlayer: FC = ({ poster, name, diff --git a/src/components/Group/GroupJoinRequests.tsx b/src/components/Group/GroupJoinRequests.tsx index b9bffc9..8c2f097 100644 --- a/src/components/Group/GroupJoinRequests.tsx +++ b/src/components/Group/GroupJoinRequests.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { useEffect, useMemo, useState } from 'react'; import List from '@mui/material/List'; import ListItem from '@mui/material/ListItem'; import ListItemButton from '@mui/material/ListItemButton'; @@ -27,12 +27,10 @@ export const GroupJoinRequests = ({ setMobileViewMode, setDesktopViewMode, }) => { - const [isExpanded, setIsExpanded] = React.useState(false); + const [isExpanded, setIsExpanded] = useState(false); const { t } = useTranslation(['auth', 'core', 'group']); - const [groupsWithJoinRequests, setGroupsWithJoinRequests] = React.useState( - [] - ); - const [loading, setLoading] = React.useState(true); + const [groupsWithJoinRequests, setGroupsWithJoinRequests] = useState([]); + const [loading, setLoading] = useState(true); const [txList] = useAtom(txListAtom); const setMyGroupsWhereIAmAdmin = useSetAtom(myGroupsWhereIAmAdminAtom); @@ -91,7 +89,7 @@ export const GroupJoinRequests = ({ } }; - React.useEffect(() => { + useEffect(() => { if (myAddress && groups.length > 0) { getJoinRequests(); } else { @@ -99,7 +97,7 @@ export const GroupJoinRequests = ({ } }, [myAddress, groups]); - const filteredJoinRequests = React.useMemo(() => { + const filteredJoinRequests = useMemo(() => { return groupsWithJoinRequests.map((group) => { const filteredGroupRequests = group?.data?.filter((gd) => { const findJoinRequsetInTxList = txList?.find( @@ -271,8 +269,15 @@ export const GroupJoinRequests = ({ fontSize: '13px', 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', + } + )} /> diff --git a/src/components/Group/ListOfThreadPostsWatched.tsx b/src/components/Group/ListOfThreadPostsWatched.tsx index 024612f..e0c4820 100644 --- a/src/components/Group/ListOfThreadPostsWatched.tsx +++ b/src/components/Group/ListOfThreadPostsWatched.tsx @@ -174,8 +174,11 @@ export const ListOfThreadPostsWatched = () => { } > - diff --git a/src/components/QortPayment.tsx b/src/components/QortPayment.tsx index 48074c6..c031914 100644 --- a/src/components/QortPayment.tsx +++ b/src/components/QortPayment.tsx @@ -1,15 +1,7 @@ -import { Box, CircularProgress, useTheme } from '@mui/material'; +import { Box, useTheme } from '@mui/material'; import { useState } from 'react'; -import { - CustomButton, - CustomInput, - CustomLabel, - TextP, -} from '../styles/App-styles'; +import { TextP } from '../styles/App-styles'; 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 { useTranslation } from 'react-i18next'; @@ -28,22 +20,37 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => { setSendPaymentError(''); setSendPaymentSuccess(''); if (!paymentTo) { - setSendPaymentError('Please enter a recipient'); + setSendPaymentError( + t('auth:action.enter_recipient', { + postProcess: 'capitalizeFirstChar', + }) + ); return; } if (!paymentAmount) { - setSendPaymentError('Please enter an amount greater than 0'); + setSendPaymentError( + t('auth:action.enter_amount', { + postProcess: 'capitalizeFirstChar', + }) + ); return; } if (!paymentPassword) { - setSendPaymentError('Please enter your wallet password'); + setSendPaymentError( + t('auth:action.enter_wallet_password', { + postProcess: 'capitalizeFirstChar', + }) + ); return; } - const fee = await getFee('PAYMENT'); // TODO translate + const fee = await getFee('PAYMENT'); 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', }); @@ -89,7 +96,9 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => { textAlign: 'start', }} > - Transfer QORT + {t('core:action.transfer_qort', { + postProcess: 'capitalizeFirstChar', + })} @@ -103,7 +112,9 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => { textAlign: 'start', }} > - Balance: + {t('core:balance', { + postProcess: 'capitalizeFirstChar', + })} { - To + + {t('core:to', { + postProcess: 'capitalizeFirstChar', + })} + @@ -134,7 +149,11 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => { - Amount + + {t('core:amount', { + postProcess: 'capitalizeFirstChar', + })} + @@ -151,7 +170,9 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => { - Confirm wallet password + {t('auth:wallet.password_confirmation', { + postProcess: 'capitalizeFirstChar', + })} @@ -173,7 +194,6 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => { {sendPaymentError} - {/* {sendPaymentSuccess} */} @@ -194,7 +214,7 @@ export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => { }} /> )} - Send + {t('core:action.send', { postProcess: 'capitalizeFirstChar' })} ); diff --git a/src/hooks/useHandlePrivateApps.tsx b/src/hooks/useHandlePrivateApps.tsx index 4e694c0..1115b52 100644 --- a/src/hooks/useHandlePrivateApps.tsx +++ b/src/hooks/useHandlePrivateApps.tsx @@ -30,14 +30,20 @@ export const useHandlePrivateApps = () => { setLoadingStatePrivateApp ) => { try { - if (setLoadingStatePrivateApp) { // TODO translate - setLoadingStatePrivateApp(`Downloading and decrypting private app.`); + if (setLoadingStatePrivateApp) { + setLoadingStatePrivateApp( + t('core:message.generic.downloading_decrypting_app', { + postProcess: 'capitalizeFirstChar', + }) + ); } setOpenSnackGlobal(true); setInfoSnackCustom({ type: 'info', - message: 'Fetching app data', + message: t('core:message.generic.fetching_data', { + postProcess: 'capitalizeFirstChar', + }), duration: null, }); const urlData = `${getBaseApiReact()}/arbitrary/${ @@ -56,7 +62,11 @@ export const useHandlePrivateApps = () => { if (!responseData?.ok) { 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'); @@ -65,13 +75,25 @@ export const useHandlePrivateApps = () => { data = await responseData.text(); if (data?.error) { 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) { if (setLoadingStatePrivateApp) { - setLoadingStatePrivateApp('Error! Unable to download private app.'); + setLoadingStatePrivateApp( + t('core:message.generic.unable_download_private_app', { + postProcess: 'capitalizeFirstChar', + }) + ); } throw error; } @@ -79,23 +101,27 @@ export const useHandlePrivateApps = () => { let decryptedData; // eslint-disable-next-line no-useless-catch try { - decryptedData = await window.sendMessage( - 'DECRYPT_QORTAL_GROUP_DATA', - - { - base64: data, - groupId: privateAppProperties?.groupId, - } - ); + decryptedData = await window.sendMessage('DECRYPT_QORTAL_GROUP_DATA', { + base64: data, + groupId: privateAppProperties?.groupId, + }); if (decryptedData?.error) { if (setLoadingStatePrivateApp) { - setLoadingStatePrivateApp('Error! Unable to decrypt private app.'); + setLoadingStatePrivateApp( + t('core:message.generic.unable_decrypt_app', { + postProcess: 'capitalizeFirstChar', + }) + ); } throw new Error(decryptedData?.error); } } catch (error) { if (setLoadingStatePrivateApp) { - setLoadingStatePrivateApp('Error! Unable to decrypt private app.'); + setLoadingStatePrivateApp( + t('core:message.generic.unable_decrypt_app', { + postProcess: 'capitalizeFirstChar', + }) + ); } throw error; } @@ -107,11 +133,15 @@ export const useHandlePrivateApps = () => { if (decryptedData) { setInfoSnackCustom({ type: 'info', - message: 'Building app', + message: t('core:message.generic.building_app', { + postProcess: 'capitalizeFirstChar', + }), }); + const endpoint = await createEndpoint( `/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true` ); + const response = await fetch(endpoint, { method: 'POST', headers: { @@ -119,7 +149,9 @@ export const useHandlePrivateApps = () => { }, body: UintToObject?.app, }); + const previewPath = await response.text(); + const refreshfunc = async (tabId, privateAppProperties) => { const checkIfPreviewLinkStillWorksUrl = await createEndpoint( `/render/hash/HmtnZpcRPwisMfprUXuBp27N2xtv5cDiQjqGZo8tbZS?secret=E39WTiG4qBq3MFcMPeRZabtQuzyfHg9ZuR5SgY7nW1YH` @@ -133,6 +165,7 @@ export const useHandlePrivateApps = () => { const endpoint = await createEndpoint( `/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true` ); + const response = await fetch(endpoint, { method: 'POST', headers: { @@ -140,6 +173,7 @@ export const useHandlePrivateApps = () => { }, body: UintToObject?.app, }); + const previewPath = await response.text(); executeEvent('updateAppUrl', { tabId: tabId, @@ -174,7 +208,9 @@ export const useHandlePrivateApps = () => { }); setInfoSnackCustom({ type: 'success', - message: {t('core:message.generic.opened', { postProcess: 'capitalizeFirstChar' })}, + message: t('core:message.generic.opened', { + postProcess: 'capitalizeFirstChar', + }), }); if (setLoadingStatePrivateApp) { setLoadingStatePrivateApp(``); diff --git a/src/hooks/useQortalMessageListener.tsx b/src/hooks/useQortalMessageListener.tsx index 3105bdc..1a8670b 100644 --- a/src/hooks/useQortalMessageListener.tsx +++ b/src/hooks/useQortalMessageListener.tsx @@ -165,7 +165,7 @@ export function openIndexedDB() { reject('Error opening IndexedDB'); }; }); -} // TODO translate +} export const listOfAllQortalRequests = [ 'ADD_FOREIGN_SERVER', @@ -658,7 +658,7 @@ export const useQortalMessageListener = ( setPath(pathUrl); if (appName?.toLowerCase() === 'q-mail') { window.sendMessage('addEnteredQmailTimestamp').catch((error) => { - // error + // TODO print error }); } else if (appName?.toLowerCase() === 'q-wallets') { executeEvent('setLastEnteredTimestampPaymentEvent', {}); diff --git a/src/i18n/locales/en/auth.json b/src/i18n/locales/en/auth.json index 81e14a5..e091927 100644 --- a/src/i18n/locales/en/auth.json +++ b/src/i18n/locales/en/auth.json @@ -22,6 +22,9 @@ "create_qortal_account": "create your Qortal account by clicking NEXT below.", "choose_password": "choose new password", "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", "insert_name_address": "please insert a name or address", "publish_admin_secret_key": "publish admin secret key", diff --git a/src/i18n/locales/en/core.json b/src/i18n/locales/en/core.json index 179cf85..eaae575 100644 --- a/src/i18n/locales/en/core.json +++ b/src/i18n/locales/en/core.json @@ -70,6 +70,7 @@ "select_app_type": "select App Type", "select_category": "select Category", "select_name_app": "select Name/App", + "send": "send", "send_qort": "send QORT", "set_avatar": "set avatar", "show": "show", @@ -98,7 +99,7 @@ "apps_dashboard": "apps Dashboard", "apps_official": "official Apps", "attachment": "attachment", - "balance": "balance", + "balance": "balance:", "category": "category", "category_other": "categories", "chat": "chat", @@ -174,8 +175,10 @@ "send_failed": "failed to send", "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_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_fetch_app": "unable to build private app", + "unable_fetch_app": "unable to fetch app", "unable_publish_app": "unable to publish app", "unable_publish_image": "unable to publish image", "unable_rate": "unable to rate", @@ -186,16 +189,19 @@ "already_voted": "you've already voted.", "avatar_size": "{{ size }} KB max. for GIFS", "building": "building", + "building_app": "building app", "created_by": "created by {{ owner }}", "buy_order_request": "the Application
{{hostname}}
is requesting {{count}} buy order", "buy_order_request_other": "the Application
{{hostname}}
is requesting {{count}} buy orders", "devmode_local_node": "please use your local node for dev mode! Logout and use Local node.", "downloading": "downloading", + "downloading_decrypting_app": "downloading and decrypting private app.", "edited": "edited", "editing_message": "editing message", "encrypted": "encrypted", "encrypted_not": "not encrypted", "fee_qort": "fee: {{ message }} QORT", + "fetching_data": "fetching app data", "foreign_fee": "foreign fee: {{ message }}", "mentioned": "mentioned", "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.", "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_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": { "minting": "(minting)", @@ -280,6 +287,7 @@ "minting_status": "minting status", "name": "name", "name_app": "name/App", + "new_post_in": "new post in {{ title }}", "none": "none", "option": "option", "option_other": "options", @@ -325,6 +333,7 @@ "time": "time" }, "title": "title", + "to": "to", "tutorial": "tutorial", "user_lookup": "user lookup", "vote": "vote", diff --git a/src/i18n/locales/en/group.json b/src/i18n/locales/en/group.json index c4042bf..c58e88c 100644 --- a/src/i18n/locales/en/group.json +++ b/src/i18n/locales/en/group.json @@ -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.", "only_encrypted": "only unencrypted messages will be displayed.", "only_private_groups": "only private groups will be shown", + "pending_join_requests": "{{ group }} has {{ count }} pending join requests", "private_key_copied": "private key copied", "provide_message": "please provide a first message to the thread", "secure_place": "keep your private key in a secure place. Do not share!",