diff --git a/src/components/Chat/GroupAnnouncements.tsx b/src/components/Chat/GroupAnnouncements.tsx index 3671a51..d2a997f 100644 --- a/src/components/Chat/GroupAnnouncements.tsx +++ b/src/components/Chat/GroupAnnouncements.tsx @@ -234,7 +234,12 @@ export const GroupAnnouncements = ({ rej(response.error); }) .catch((error) => { - rej(error.message || 'An error occurred'); + rej( + error.message || + t('core:message.error.generic', { + postProcess: 'capitalizeFirst', + }) + ); }); }); } catch (error) { @@ -257,7 +262,12 @@ export const GroupAnnouncements = ({ rej(response.error); }) .catch((error) => { - rej(error.message || 'An error occurred'); + rej( + error.message || + t('core:message.error.generic', { + postProcess: 'capitalizeFirst', + }) + ); }); }); }; @@ -337,7 +347,7 @@ export const GroupAnnouncements = ({ setTempData(selectedGroup); clearEditorContent(); } - // TODO send chat message + // send chat message } catch (error) { if (!error) return; setInfoSnack({ @@ -586,7 +596,9 @@ export const GroupAnnouncements = ({ fontSize: '30px', }} /> - Group Announcements + {t('group:message.generic.group_announcement', { + postProcess: 'capitalizeFirst', + })} @@ -605,10 +617,13 @@ export const GroupAnnouncements = ({ fontSize: '16px', }} > - No announcements + {t('group:message.generic.no_announcement', { + postProcess: 'capitalizeFirst', + })} )} + - {` Close`} + {t('core:action.close', { postProcess: 'capitalizeFirst' })} )} @@ -723,7 +738,9 @@ export const GroupAnnouncements = ({ }} /> )} - {` Publish Announcement`} + {t('group:action.publish_announcement', { + postProcess: 'capitalizeFirst', + })} @@ -739,7 +756,9 @@ export const GroupAnnouncements = ({ diff --git a/src/components/Chat/GroupAvatar.tsx b/src/components/Chat/GroupAvatar.tsx index dbc25cd..caf3c4b 100644 --- a/src/components/Chat/GroupAvatar.tsx +++ b/src/components/Chat/GroupAvatar.tsx @@ -20,6 +20,7 @@ import { getFee } from '../../background'; import { fileToBase64 } from '../../utils/fileReading'; import { LoadingButton } from '@mui/lab'; import ErrorIcon from '@mui/icons-material/Error'; +import { useTranslation } from 'react-i18next'; export const GroupAvatar = ({ myName, @@ -32,7 +33,7 @@ export const GroupAvatar = ({ const [avatarFile, setAvatarFile] = useState(null); const [tempAvatar, setTempAvatar] = useState(null); const { show } = useContext(MyContext); - + const { t } = useTranslation(['auth', 'core', 'group']); const [anchorEl, setAnchorEl] = useState(null); const [isLoading, setIsLoading] = useState(false); // Handle child element click to open Popover @@ -68,6 +69,7 @@ export const GroupAvatar = ({ console.log(error); } }, []); + useEffect(() => { if (!myName || !groupId) return; checkIfAvatarExists(myName, groupId); @@ -79,14 +81,22 @@ export const GroupAvatar = ({ const fee = await getFee('ARBITRARY'); if (+balance < +fee.fee) - throw new Error(`Publishing an Avatar requires ${fee.fee}`); + throw new Error( + t('core:message.generic.avatar_publish_fee', { + fee: fee.fee, + postProcess: 'capitalizeFirst', + }) + ); await show({ - message: 'Would you like to publish an avatar?', + message: t('core:question.publish_avatar', { + postProcess: 'capitalizeFirst', + }), publishFee: fee.fee + ' QORT', }); setIsLoading(true); const avatarBase64 = await fileToBase64(avatarFile); + await new Promise((res, rej) => { window .sendMessage('publishOnQDN', { @@ -102,7 +112,12 @@ export const GroupAvatar = ({ rej(response.error); }) .catch((error) => { - rej(error.message || 'An error occurred'); + rej( + error.message || + t('core:message.error.generic', { + postProcess: 'capitalizeFirst', + }) + ); }); }); setAvatarFile(null); @@ -142,7 +157,7 @@ export const GroupAvatar = ({ opacity: 0.5, }} > - change avatar + {t('core:action.change_avatar', { postProcess: 'capitalizeFirst' })} @@ -182,7 +197,7 @@ export const GroupAvatar = ({ opacity: 0.5, }} > - change avatar + {t('core:action.change_avatar', { postProcess: 'capitalizeFirst' })} @@ -211,7 +226,7 @@ export const GroupAvatar = ({ opacity: 0.5, }} > - set avatar + {t('core:action.set_avatar', { postProcess: 'capitalizeFirst' })} @@ -242,6 +257,8 @@ const PopoverComp = ({ myName, }) => { const theme = useTheme(); + const { t } = useTranslation(['auth', 'core', 'group']); + return ( - (500 KB max. for GIFS){' '} + {t('core:message.generic.avatar_size', { + size: 500, // TODO magic number + postProcess: 'capitalizeFirst', + })} setAvatarFile(file)}> - + {avatarFile?.name} @@ -277,9 +299,9 @@ const PopoverComp = ({ {!myName && ( - A registered name is required to set an avatar + {t('core:message.generic.avatar_registered_name', { + postProcess: 'capitalizeFirst', + })} )} @@ -301,7 +325,7 @@ const PopoverComp = ({ onClick={publishAvatar} variant="contained" > - Publish avatar + {t('group:action.publish_avatar', { postProcess: 'capitalizeFirst' })} diff --git a/src/components/Chat/MentionList.tsx b/src/components/Chat/MentionList.tsx index 06cea5c..e9f0f86 100644 --- a/src/components/Chat/MentionList.tsx +++ b/src/components/Chat/MentionList.tsx @@ -1,6 +1,9 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from 'react'; +import { useTranslation } from 'react-i18next'; export default forwardRef((props, ref) => { + const { t } = useTranslation(['auth', 'core', 'group']); + const [selectedIndex, setSelectedIndex] = useState(0); const selectItem = (index) => { @@ -61,7 +64,11 @@ export default forwardRef((props, ref) => { )) ) : ( -
No result
+
+ {t('core:message.generic.no_results', { + postProcess: 'capitalizeFirst', + })} +
)} ); diff --git a/src/components/Chat/MessageItem.tsx b/src/components/Chat/MessageItem.tsx index 7b72d79..cc19ee3 100644 --- a/src/components/Chat/MessageItem.tsx +++ b/src/components/Chat/MessageItem.tsx @@ -48,6 +48,7 @@ import level9Img from '../../assets/badges/level-9.png'; import level10Img from '../../assets/badges/level-10.png'; import { Embed } from '../Embeds/Embed'; import { buildImageEmbedLink, messageHasImage } from '../../utils/chat'; +import { useTranslation } from 'react-i18next'; const getBadgeImg = (level) => { switch (level?.toString()) { @@ -169,12 +170,15 @@ export const MessageItem = memo( }, [message?.id]); const theme = useTheme(); + const { t } = useTranslation(['auth', 'core', 'group']); return ( <> {message?.divide && (
- Unread messages below + {t('core:message.generic.unread_messages', { + postProcess: 'capitalizeFirst', + })}
)} @@ -262,6 +266,7 @@ export const MessageItem = memo( {message?.senderName || message?.sender} + )} + {!isShowingAsReply && ( { @@ -288,6 +294,7 @@ export const MessageItem = memo( )} + {!isShowingAsReply && handleReaction && ( { @@ -307,6 +314,7 @@ export const MessageItem = memo( )} + {reply && ( <> @@ -333,6 +341,7 @@ export const MessageItem = memo( flexShrink: 0, }} /> + - Replied to {reply?.senderName || reply?.senderAddress} + {t('core:message.generic.replied_to', { + person: reply?.senderName || reply?.senderAddress, + postProcess: 'capitalizeFirst', + })} + {reply?.messageText && ( )} + {reply?.decryptedData?.type === 'notification' ? ( )} + {htmlText && } {message?.decryptedData?.type === 'notification' ? ( @@ -454,14 +469,17 @@ export const MessageItem = memo( > - People who reacted with {selectedReaction} + {t('core:message.generic.people_reaction', { + reaction: selectedReaction, + postProcess: 'capitalizeFirst', + })} {reactions[selectedReaction]?.map((reactionItem) => ( @@ -474,6 +492,7 @@ export const MessageItem = memo( ))} + )} + {message?.status === 'failed-permanent' - ? 'Failed to update' - : 'Updating...'} + ? t('core:message.error.update_failed', { + postProcess: 'capitalizeFirst', + }) + : t('core:message.generic.updating', { + postProcess: 'capitalizeFirst', + })} ) : isTemp ? ( {message?.status === 'failed-permanent' - ? 'Failed to send' - : 'Sending...'} + ? t('core:message.error.send_failed', { + postProcess: 'capitalizeFirst', + }) + : t('core:message.generic.sending', { + postProcess: 'capitalizeFirst', + })} ) : ( <> @@ -552,7 +584,9 @@ export const MessageItem = memo( fontStyle: 'italic', }} > - Edited + {t('core:message.generic.edited', { + postProcess: 'capitalizeFirst', + })} )} { const theme = useTheme(); + const { t } = useTranslation(['auth', 'core', 'group']); return ( { fontWeight: 600, }} > - Editing Message + {t('core:message.generic.editing_message', { + postProcess: 'capitalizeFirst', + })} ) : ( { fontWeight: 600, }} > - Replied to {message?.senderName || message?.senderAddress} + {t('core:message.generic.replied_to', { + person: message?.senderName || message?.senderAddress, + postProcess: 'capitalizeFirst', + })} )} diff --git a/src/components/Chat/TipTap.tsx b/src/components/Chat/TipTap.tsx index 94894ab..cc315fe 100644 --- a/src/components/Chat/TipTap.tsx +++ b/src/components/Chat/TipTap.tsx @@ -31,6 +31,8 @@ import { isDisabledEditorEnterAtom } from '../../atoms/global.js'; import { Box, Checkbox, Typography, useTheme } from '@mui/material'; import { useAtom } from 'jotai'; import { fileToBase64 } from '../../utils/fileReading/index.js'; +import { useTranslation } from 'react-i18next'; +import { t } from 'i18next'; function textMatcher(doc, from) { const textBeforeCursor = doc.textBetween(0, from, ' ', ' '); @@ -52,6 +54,7 @@ const MenuBar = memo( const { editor } = useCurrentEditor(); const fileInputRef = useRef(null); const theme = useTheme(); + const { t } = useTranslation(['auth', 'core', 'group']); useEffect(() => { if (editor && setEditorRef) { @@ -143,6 +146,7 @@ const MenuBar = memo( > + editor.chain().focus().toggleItalic().run()} disabled={!editor.can().chain().focus().toggleItalic().run()} @@ -155,6 +159,7 @@ const MenuBar = memo( > + editor.chain().focus().toggleStrike().run()} disabled={!editor.can().chain().focus().toggleStrike().run()} @@ -167,6 +172,7 @@ const MenuBar = memo( > + editor.chain().focus().toggleCode().run()} disabled={!editor.can().chain().focus().toggleCode().run()} @@ -179,6 +185,7 @@ const MenuBar = memo( > + editor.chain().focus().unsetAllMarks().run()} sx={{ @@ -194,6 +201,7 @@ const MenuBar = memo( > + editor.chain().focus().toggleBulletList().run()} sx={{ @@ -205,6 +213,7 @@ const MenuBar = memo( > + editor.chain().focus().toggleOrderedList().run()} sx={{ @@ -216,6 +225,7 @@ const MenuBar = memo( > + editor.chain().focus().toggleCodeBlock().run()} sx={{ @@ -227,6 +237,7 @@ const MenuBar = memo( > + editor.chain().focus().toggleBlockquote().run()} sx={{ @@ -238,6 +249,7 @@ const MenuBar = memo( > + editor.chain().focus().setHorizontalRule().run()} disabled={!editor.can().chain().focus().setHorizontalRule().run()} @@ -245,6 +257,7 @@ const MenuBar = memo( > + editor.chain().focus().toggleHeading({ level: 1 }).run() @@ -258,6 +271,7 @@ const MenuBar = memo( > + editor.chain().focus().undo().run()} disabled={!editor.can().chain().focus().undo().run()} @@ -265,6 +279,7 @@ const MenuBar = memo( > + editor.chain().focus().redo().run()} disabled={!editor.can().chain().focus().redo().run()} @@ -272,13 +287,14 @@ const MenuBar = memo( > + {isChat && ( { setIsDisabledEditorEnter(!isDisabledEditorEnter); @@ -304,10 +320,13 @@ const MenuBar = memo( color: theme.palette.text.primary, }} > - disable enter + {t('core:action.disable_enter', { + postProcess: 'capitalizeFirst', + })} )} + {!isChat && ( <> + { return (membersWithNames || [])?.map((item) => { return { diff --git a/src/i18n/locales/en/core.json b/src/i18n/locales/en/core.json index bf54cee..39f8358 100644 --- a/src/i18n/locales/en/core.json +++ b/src/i18n/locales/en/core.json @@ -2,6 +2,7 @@ "action": { "add": "add", "add_custom_framework": "add custom framework", + "add_reaction": "add reaction", "accept": "accept", "access": "access", "backup_account": "backup account", @@ -9,10 +10,12 @@ "cancel": "cancel", "cancel_invitation": "cancel invitation", "change": "change", + "change_avatar": "change avatar", "change_file": "change file", "change_language": "change language", "choose": "choose", "choose_file": "choose file", + "choose_image": "choose image", "close": "close", "close_chat": "close Direct Chat", "continue": "continue", @@ -25,6 +28,7 @@ "choose_name": "choose a name", "decline": "decline", "decrypt": "decrypt", + "disable_enter": "disable enter", "download": "download", "edit": "edit", "enter_name": "enter a name", @@ -54,6 +58,7 @@ "publish_comment": "publish comment", "register_name": "register name", "remove": "remove", + "remove_reaction": "remove reaction", "return_apps_dashboard": "return to Apps Dashboard", "save": "save", "search": "search", @@ -61,7 +66,9 @@ "select_app_type": "select App Type", "select_category": "select Category", "select_name_app": "select Name/App", + "set_avatar": "set avatar", "start_minting": "start minting", + "start_typing": "start typing here...", "transfer_qort": "Transfer QORT", "unpin": "unpin", "unpin_app": "unpin app", @@ -113,6 +120,7 @@ "member": "member list" }, "loading": { + "announcements": "announcements", "generic": "loading...", "chat": "loading chat... please wait.", "comments": "loading comments... please wait.", @@ -139,15 +147,20 @@ "publish_app": "unable to publish app", "rating_option": "cannot find rating option", "save_qdn": "unable to save to QDN", + "send_failed": "failed to send", "unable_encrypt_app": "unable to encrypt app. App not published'", "unable_publish_app": "unable to publish app", "unable_publish_image": "unable to publish image", - "unable_rate": "unable to rate" + "unable_rate": "unable to rate", + "update_failed": "failed to update" }, "generic": { + "avatar_size": "{{ size }} KB max. for GIFS", "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.", + "edited": "edited", + "editing_message": "editing message", "fee_qort": "fee: {{ message }} QORT", "foreign_fee": "foreign fee: {{ message }}", "mentioned": "mentioned", @@ -170,11 +183,13 @@ "password_confirm": "please confirm a password", "password_enter": "please enter a password", "payment_request": "the Application
{{hostname}}
is requesting a payment", + "people_reaction": "people who reacted with {{ reaction }}", "publish_data": "publish data to Qortal: anything from apps to videos. Fully decentralized!", "publishing": "publishing... Please wait.", "qdn": "use QDN saving", "rating": "rating for {{ service }} {{ name }}", "register_name": "you need a registered Qortal name to save your pinned apps to QDN.", + "replied_to": "replied to {{ person }}", "revert_default": "revert to default", "revert_qdn": "revert to QDN", "save_qdn": "save to QDN", @@ -182,9 +197,12 @@ "select_file": "please select a file", "select_image": "please select an image for a logo", "select_zip": "select .zip file containing static content:", + "sending": "sending...", "settings": "you are using the export/import way of saving settings.", "space_for_admins": "sorry, this space is only for Admins.", - "unsaved_changes": "you have unsaved changes to your pinned apps. Save them to QDN." + "unread_messages": "unread messages below", + "unsaved_changes": "you have unsaved changes to your pinned apps. Save them to QDN.", + "updating": "updating" }, "question": { "logout": "are you sure you would like to logout?", @@ -229,6 +247,7 @@ "perform_transaction": "would you like to perform a {{action}} transaction?", "provide_thread": "please provide a thread title", "publish_app": "would you like to publish this app?", + "publish_avatar": "would you like to publish an avatar?", "publish_qdn": "would you like to publish your settings to QDN (encrypted)?", "overwrite_changes": "the app was unable to download your existing QDN-saved pinned apps. Would you like to overwrite those changes?", "rate_app": "would you like to rate this app a rating of {{ rate }}?. It will create a POLL tx.", diff --git a/src/i18n/locales/en/group.json b/src/i18n/locales/en/group.json index c161605..8ad2d6b 100644 --- a/src/i18n/locales/en/group.json +++ b/src/i18n/locales/en/group.json @@ -18,6 +18,8 @@ "make_admin": "make an admin", "manage_members": "manage members", "promote_group": "promote your group to non-members", + "publish_announcement": "publish announcement", + "publish_avatar": "publish avatar", "refetch_page": "refetch page", "remove_admin": "remove as admin", "remove_minting_account": "remove minting account", @@ -57,11 +59,14 @@ "latest_mails": "latest Q-Mails", "message": { "generic": { + "avatar_publish_fee": "publishing an Avatar requires {{ fee }}", + "avatar_registered_name": "a registered name is required to set an avatar", "admin_only": "only groups where you are an admin will be shown", "already_in_group": "you are already in this group!", "closed_group": "this is a closed/private group, so you will need to wait until an admin accepts your request", "descrypt_wallet": "decrypting wallet...", "encryption_key": "the group's first common encryption key is in the process of creation. Please wait a few minutes for it to be retrieved by the network. Checking every 2 minutes...", + "group_announcement": "group Announcements", "group_invited_you": "{{group}} has invited you", "group_key_created": "first group key created.", "group_member_list_changed": "the group member list has changed. Please re-encrypt the secret key.", @@ -82,6 +87,7 @@ "node_minting": "This node is minting:", "node_minting_account": "node's minting accounts", "node_minting_key": "you currently have a minting key for this account attached to this node", + "no_announcement": "no announcements", "no_display": "nothing to display", "no_selection": "no group selected", "not_part_group": "you are not part of the encrypted group of members. Wait until an admin re-encrypts the keys.",