From ed6a5346df5eac231e3ffb620bb4fdb625c7acee Mon Sep 17 00:00:00 2001 From: Ron Metzger Date: Thu, 23 Jan 2025 13:27:54 +0100 Subject: [PATCH 1/3] changed language support for following windows: chat, data-upload and account settings --- .../Connectors/Confluence/index.jsx | 44 +++-- .../Connectors/Github/index.jsx | 57 +++--- .../Connectors/Gitlab/index.jsx | 57 +++--- .../Connectors/WebsiteDepth/index.jsx | 18 +- .../Connectors/Youtube/index.jsx | 19 +- .../ManageWorkspace/DataConnectors/index.jsx | 34 ++-- .../Documents/Directory/index.jsx | 20 +- .../Documents/UploadFile/index.jsx | 21 +- .../Documents/WorkspaceDirectory/index.jsx | 51 +++-- .../Modals/ManageWorkspace/index.jsx | 14 +- .../UserMenu/AccountModal/index.jsx | 33 ++-- .../ChatContainer/ChatHistory/index.jsx | 12 +- .../PromptInput/AgentMenu/index.jsx | 6 +- .../PromptInput/AttachItem/index.jsx | 6 +- .../PromptInput/SlashCommands/index.jsx | 4 +- .../PromptInput/SpeechToText/index.jsx | 7 +- .../PromptInput/TextSizeMenu/index.jsx | 6 +- .../ChatContainer/PromptInput/index.jsx | 8 +- frontend/src/locales/de/common.js | 181 +++++++++++++++++- frontend/src/locales/en/common.js | 178 +++++++++++++++++ frontend/src/locales/es/common.js | 178 +++++++++++++++++ frontend/src/locales/fa/common.js | 178 +++++++++++++++++ frontend/src/locales/fr/common.js | 178 +++++++++++++++++ frontend/src/locales/he/common.js | 178 +++++++++++++++++ frontend/src/locales/it/common.js | 178 +++++++++++++++++ frontend/src/locales/ko/common.js | 178 +++++++++++++++++ frontend/src/locales/nl/common.js | 178 +++++++++++++++++ frontend/src/locales/pt_BR/common.js | 178 +++++++++++++++++ frontend/src/locales/ru/common.js | 178 +++++++++++++++++ frontend/src/locales/vn/common.js | 178 +++++++++++++++++ frontend/src/locales/zh/common.js | 178 +++++++++++++++++ frontend/src/locales/zh_TW/common.js | 178 +++++++++++++++++ 32 files changed, 2721 insertions(+), 191 deletions(-) diff --git a/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Confluence/index.jsx b/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Confluence/index.jsx index 6204442012b..939a697f2fe 100644 --- a/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Confluence/index.jsx +++ b/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Confluence/index.jsx @@ -1,10 +1,12 @@ import { useState } from "react"; +import { useTranslation } from "react-i18next"; import System from "@/models/system"; import showToast from "@/utils/toast"; import { Warning } from "@phosphor-icons/react"; import { Tooltip } from "react-tooltip"; export default function ConfluenceOptions() { + const { t } = useTranslation(); const [loading, setLoading] = useState(false); const handleSubmit = async (e) => { @@ -59,12 +61,11 @@ export default function ConfluenceOptions() {

- Determine if your Confluence instance is hosted on Atlassian - cloud or self-hosted. + {t("connectors.confluence.deployment_type_explained")}

- This is the spaces key of your confluence instance that will - be used. Usually begins with ~ + {t("connectors.confluence.space_key_explained")}

- Your Confluence username. + {t("connectors.confluence.username_explained")}

- Access token for authentication. + {t("connectors.confluence.token_desc")}

{loading && (

- Once complete, all pages will be available for embedding into - workspaces. + {t("connectors.confluence.task_explained")}

)} diff --git a/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Github/index.jsx b/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Github/index.jsx index c7bd2f22096..88d6d9c5e65 100644 --- a/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Github/index.jsx +++ b/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Github/index.jsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from "react"; import System from "@/models/system"; +import { useTranslation } from "react-i18next"; import showToast from "@/utils/toast"; import pluralize from "pluralize"; import { TagsInput } from "react-tag-input-component"; @@ -8,6 +9,7 @@ import { Tooltip } from "react-tooltip"; const DEFAULT_BRANCHES = ["main", "master"]; export default function GithubOptions() { + const { t } = useTranslation(); const [loading, setLoading] = useState(false); const [repo, setRepo] = useState(null); const [accessToken, setAccessToken] = useState(null); @@ -68,10 +70,10 @@ export default function GithubOptions() {

- Url of the GitHub repo you wish to collect. + {t('connectors.github.URL_explained')}

- Access Token to prevent rate limiting. + {t('connectors.github.token_explained')}

- List in .gitignore format to ignore specific files during - collection. Press enter after each entry you want to save. + {t('connectors.github.git_ignore')} +

{loading && (

- Once complete, all files will be available for embedding into - workspaces in the document picker. + {t('connectors.github.task_explained')} +

)}
@@ -166,6 +172,7 @@ export default function GithubOptions() { } function GitHubBranchSelection({ repo, accessToken }) { + const { t } = useTranslation(); const [allBranches, setAllBranches] = useState(DEFAULT_BRANCHES); const [loading, setLoading] = useState(true); @@ -194,7 +201,9 @@ function GitHubBranchSelection({ repo, accessToken }) {

- Branch you wish to collect files from. + + {t('connectors.github.branch')} +

@@ -215,7 +224,7 @@ function GitHubBranchSelection({ repo, accessToken }) {

- Branch you wish to collect files from. + {t('connectors.github.branch_explained')}

- Access Token to prevent rate limiting. + {t("connectors.gitlab.token_description")}

Settings

{" "}

- Select additional entities to fetch from the GitLab API. + {t("connectors.gitlab.token_description")}

@@ -132,7 +134,7 @@ export default function GitlabOptions() { />
- Fetch Issues as Documents + {t("connectors.gitlab.fetch_issues")}
@@ -146,11 +148,10 @@ export default function GitlabOptions() {

- List in .gitignore format to ignore specific files during - collection. Press enter after each entry you want to save. + {t("connectors.gitlab.git_ignore")}

{loading && (

- Once complete, all files will be available for embedding into - workspaces in the document picker. + {t("connectors.gitlab.task_explained")}

)}
@@ -190,6 +190,7 @@ export default function GitlabOptions() { } function GitLabBranchSelection({ repo, accessToken }) { + const { t } = useTranslation(); const [allBranches, setAllBranches] = useState(DEFAULT_BRANCHES); const [loading, setLoading] = useState(true); @@ -216,9 +217,9 @@ function GitLabBranchSelection({ repo, accessToken }) { return (
- +

- Branch you wish to collect files from. + {t("connectors.gitlab.branch_explained")}

@@ -239,7 +240,7 @@ function GitLabBranchSelection({ repo, accessToken }) {

- Branch you wish to collect files from. + {t("connectors.gitlab.branch_explained")}

- +

- This is the number of child-links that the worker should - follow from the origin URL. + {t("connectors.website-depth.depth_explained")}

- Maximum number of links to scrape. + {t("connectors.website-depth.max_pages_explained")}

{loading && (

- Once complete, all scraped pages will be available for embedding - into workspaces in the document picker. + {t("connectors.website-depth.task_explained")}

)}
diff --git a/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Youtube/index.jsx b/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Youtube/index.jsx index 3f162ac131c..0ef4a81b8a7 100644 --- a/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Youtube/index.jsx +++ b/frontend/src/components/Modals/ManageWorkspace/DataConnectors/Connectors/Youtube/index.jsx @@ -1,8 +1,10 @@ import React, { useState } from "react"; import System from "@/models/system"; import showToast from "@/utils/toast"; +import { useTranslation } from "react-i18next"; export default function YoutubeOptions() { + const { t } = useTranslation(); const [loading, setLoading] = useState(false); const handleSubmit = async (e) => { @@ -50,10 +52,20 @@ export default function YoutubeOptions() {

- URL of the YouTube video you wish to transcribe. + {t("connectors.youtube.URL_explained_start")} + e.stopPropagation()} + > + {t("connectors.youtube.URL_explained_link")} + + {t("connectors.youtube.URL_explained_end")}

{loading && (

- Once complete, the transcription will be available for embedding - into workspaces in the document picker. + {t("connectors.youtube.task_explained")}

)}
diff --git a/frontend/src/components/Modals/ManageWorkspace/DataConnectors/index.jsx b/frontend/src/components/Modals/ManageWorkspace/DataConnectors/index.jsx index 647a026f6f5..2eacde6cfd1 100644 --- a/frontend/src/components/Modals/ManageWorkspace/DataConnectors/index.jsx +++ b/frontend/src/components/Modals/ManageWorkspace/DataConnectors/index.jsx @@ -1,5 +1,6 @@ import ConnectorImages from "@/components/DataConnectorOption/media"; import { MagnifyingGlass } from "@phosphor-icons/react"; +import { useTranslation } from "react-i18next"; import GithubOptions from "./Connectors/Github"; import GitlabOptions from "./Connectors/Gitlab"; import YoutubeOptions from "./Connectors/Youtube"; @@ -8,45 +9,44 @@ import { useState } from "react"; import ConnectorOption from "./ConnectorOption"; import WebsiteDepthOptions from "./Connectors/WebsiteDepth"; -export const DATA_CONNECTORS = { +export const getDataConnectors = (t) => ({ github: { - name: "GitHub Repo", + name: t('connectors.github.name'), image: ConnectorImages.github, - description: - "Import an entire public or private Github repository in a single click.", + description: t('connectors.github.description'), options: , }, gitlab: { - name: "GitLab Repo", + name: t('connectors.gitlab.name'), image: ConnectorImages.gitlab, - description: - "Import an entire public or private GitLab repository in a single click.", + description: t('connectors.gitlab.description'), options: , }, "youtube-transcript": { - name: "YouTube Transcript", + name: t('connectors.youtube.name'), image: ConnectorImages.youtube, - description: - "Import the transcription of an entire YouTube video from a link.", + description: t('connectors.youtube.description'), options: , }, "website-depth": { - name: "Bulk Link Scraper", + name: t('connectors.website-depth.name'), image: ConnectorImages.websiteDepth, - description: "Scrape a website and its sub-links up to a certain depth.", + description: t('connectors.website-depth.description'), options: , }, confluence: { - name: "Confluence", + name: t('connectors.confluence.name'), image: ConnectorImages.confluence, - description: "Import an entire Confluence page in a single click.", + description: t('connectors.confluence.description'), options: , }, -}; +}); export default function DataConnectors() { + const { t } = useTranslation(); const [selectedConnector, setSelectedConnector] = useState("github"); const [searchQuery, setSearchQuery] = useState(""); + const DATA_CONNECTORS = getDataConnectors(t); const filteredConnectors = Object.keys(DATA_CONNECTORS).filter((slug) => DATA_CONNECTORS[slug].name.toLowerCase().includes(searchQuery.toLowerCase()) @@ -63,7 +63,7 @@ export default function DataConnectors() { /> - No data connectors found. + {t('connectors.no-connectors')} )} diff --git a/frontend/src/components/Modals/ManageWorkspace/Documents/Directory/index.jsx b/frontend/src/components/Modals/ManageWorkspace/Documents/Directory/index.jsx index d29e893578b..2c2cbdc1072 100644 --- a/frontend/src/components/Modals/ManageWorkspace/Documents/Directory/index.jsx +++ b/frontend/src/components/Modals/ManageWorkspace/Documents/Directory/index.jsx @@ -1,6 +1,7 @@ import UploadFile from "../UploadFile"; import PreLoader from "@/components/Preloader"; import { memo, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; import FolderRow from "./FolderRow"; import System from "@/models/system"; import { MagnifyingGlass, Plus, Trash } from "@phosphor-icons/react"; @@ -30,6 +31,7 @@ function Directory({ setLoadingMessage, loadingMessage, }) { + const { t } = useTranslation(); const [amountSelected, setAmountSelected] = useState(0); const [showFolderSelection, setShowFolderSelection] = useState(false); const [searchTerm, setSearchTerm] = useState(""); @@ -51,9 +53,7 @@ function Directory({ const deleteFiles = async (event) => { event.stopPropagation(); if ( - !window.confirm( - "Are you sure you want to delete these files and folders?\nThis will remove the files from the system and remove them from any existing workspaces automatically.\nThis action is not reversible." - ) + !window.confirm(t('connectors.directory.delete-confirmation')) ) { return false; } @@ -83,7 +83,7 @@ function Directory({ setLoading(true); setLoadingMessage( - `Removing ${toRemove.length} documents and ${foldersToRemove.length} folders. Please wait.` + t('connectors.directory.removing-message', { count: toRemove.length, folderCount: foldersToRemove.length }) ); await System.deleteDocuments(toRemove); for (const folderName of foldersToRemove) { @@ -166,7 +166,7 @@ function Directory({ // show info if some files were not moved due to being embedded showToast(message, "info"); } else { - showToast(`Successfully moved ${toMove.length} documents.`, "success"); + showToast(t('connectors.directory.move-success', { count: toMove.length }), "success"); } await fetchKeys(true); setSelectedItems({}); @@ -194,11 +194,11 @@ function Directory({
-

My Documents

+

{t('connectors.directory.my-documents')}

@@ -218,7 +218,7 @@ function Directory({ className="text-theme-text-primary light:text-[#0ba5ec]" />
- New Folder + {t('connectors.directory.new-folder')}
@@ -257,7 +257,7 @@ function Directory({ ) : (

- No Documents + {t('connectors.directory.no-documents')}

)} @@ -272,7 +272,7 @@ function Directory({ onMouseLeave={() => setHighlightWorkspace(false)} className="border-none text-sm font-semibold bg-white light:bg-[#E0F2FE] h-[30px] px-2.5 rounded-lg hover:bg-neutral-800/80 hover:text-white light:text-[#026AA2] light:hover:bg-[#026AA2] light:hover:text-white" > - Move to Workspace + {t('connectors.directory.move-workspace')}
) : files.length === 0 ? (
- Click to upload or drag and drop + {t('connectors.upload.click-upload')}
- supports text files, csv's, spreadsheets, audio files, and more! + {t('connectors.upload.file-types')}
) : ( @@ -128,7 +129,7 @@ export default function UploadFile({ )}
- or submit a link + {t('connectors.upload.or-submit-link')}
- These files will be uploaded to the document processor running on this - AnythingLLM instance. These files are not sent or shared with a third - party. + {t('connectors.upload.privacy-notice')}
); diff --git a/frontend/src/components/Modals/ManageWorkspace/Documents/WorkspaceDirectory/index.jsx b/frontend/src/components/Modals/ManageWorkspace/Documents/WorkspaceDirectory/index.jsx index 18a73de8ff9..c351edb7f17 100644 --- a/frontend/src/components/Modals/ManageWorkspace/Documents/WorkspaceDirectory/index.jsx +++ b/frontend/src/components/Modals/ManageWorkspace/Documents/WorkspaceDirectory/index.jsx @@ -10,6 +10,7 @@ import { Link } from "react-router-dom"; import Workspace from "@/models/workspace"; import { Tooltip } from "react-tooltip"; import { safeJsonParse } from "@/utils/request"; +import { useTranslation } from "react-i18next"; function WorkspaceDirectory({ workspace, @@ -25,6 +26,7 @@ function WorkspaceDirectory({ embeddingCosts, movedItems, }) { + const { t } = useTranslation(); const [selectedItems, setSelectedItems] = useState({}); const toggleSelection = (item) => { @@ -182,7 +184,7 @@ function WorkspaceDirectory({ ) : (

- No Documents + {t("connectors.directory.no_docs")}

)} @@ -201,14 +203,14 @@ function WorkspaceDirectory({ (sum, folder) => sum + folder.items.length, 0 ) - ? "Deselect All" - : "Select All"} + ? t("connectors.directory.deselect_all") + : t("connectors.directory.select_all")}
@@ -229,7 +231,7 @@ function WorkspaceDirectory({ }`}

@@ -237,7 +239,7 @@ function WorkspaceDirectory({ onClick={(e) => handleSaveChanges(e)} className="border border-slate-200 px-5 py-2.5 rounded-lg text-white text-sm items-center flex gap-x-2 hover:bg-slate-200 hover:text-slate-800 focus:ring-gray-800" > - Save and Embed + {t("connectors.directory.save_embed")} )} @@ -250,6 +252,7 @@ function WorkspaceDirectory({ } const PinAlert = memo(() => { + const { t } = useTranslation(); const [showAlert, setShowAlert] = useState(false); function dismissAlert() { setShowAlert(false); @@ -277,25 +280,20 @@ const PinAlert = memo(() => { weight="regular" />

- What is document pinning? + {t("connectors.pinning.what_pinning")}

- When you pin a document in AnythingLLM we will inject the - entire content of the document into your prompt window for your - LLM to fully comprehend. +

- This works best with large-context models or small files - that are critical to its knowledge-base. +

- If you are not getting the answers you desire from AnythingLLM by - default then pinning is a great way to get higher quality answers - in a click. + {t("connectors.pinning.pin_explained_block3")}

@@ -304,7 +302,7 @@ const PinAlert = memo(() => { onClick={dismissAlert} className="transition-all duration-300 bg-white text-black hover:opacity-60 px-4 py-2 rounded-lg text-sm" > - Okay, got it + {t("connectors.pinning.accept")} @@ -313,6 +311,7 @@ const PinAlert = memo(() => { }); const DocumentWatchAlert = memo(() => { + const { t } = useTranslation(); const [showAlert, setShowAlert] = useState(false); function dismissAlert() { setShowAlert(false); @@ -340,31 +339,27 @@ const DocumentWatchAlert = memo(() => { weight="regular" />

- What does watching a document do? + {t("connectors.pinning.what_watching")}

- When you watch a document in AnythingLLM we will{" "} - automatically sync your document content from it's original - source on regular intervals. This will automatically update the - content in every workspace where this file is managed. +

- This feature currently supports online-based content and will not - be available for manually uploaded documents. + {t("connectors.watching.watch_explained_block2")}

- You can manage what documents are watched from the{" "} + {t("connectors.watching.watch_explained_block3_start")} - File manager - {" "} - admin view. + {t("connectors.watching.watch_explained_block3_link")} + + {t("connectors.watching.watch_explained_block3_end")}

@@ -373,7 +368,7 @@ const DocumentWatchAlert = memo(() => { onClick={dismissAlert} className="transition-all duration-300 bg-white text-black hover:opacity-60 px-4 py-2 rounded-lg text-sm" > - Okay, got it + {t("connectors.watching.accept")} diff --git a/frontend/src/components/Modals/ManageWorkspace/index.jsx b/frontend/src/components/Modals/ManageWorkspace/index.jsx index 33c9fa8cbf2..199e453592e 100644 --- a/frontend/src/components/Modals/ManageWorkspace/index.jsx +++ b/frontend/src/components/Modals/ManageWorkspace/index.jsx @@ -1,5 +1,6 @@ import React, { useState, useEffect, memo } from "react"; import { X } from "@phosphor-icons/react"; +import { useTranslation } from "react-i18next"; import { useParams } from "react-router-dom"; import Workspace from "../../../models/workspace"; import System from "../../../models/system"; @@ -11,6 +12,7 @@ import ModalWrapper from "@/components/ModalWrapper"; const noop = () => {}; const ManageWorkspace = ({ hideModal = noop, providedSlug = null }) => { + const { t } = useTranslation(); const { slug } = useParams(); const { user } = useUser(); const [workspace, setWorkspace] = useState(null); @@ -42,7 +44,7 @@ const ManageWorkspace = ({ hideModal = noop, providedSlug = null }) => {

- Editing "{workspace.name}" + {t('connectors.manage.editing')} "{workspace.name}"

@@ -70,7 +71,7 @@ const ManageWorkspace = ({ hideModal = noop, providedSlug = null }) => { type="button" className="transition-all duration-300 bg-white text-black hover:opacity-60 px-4 py-2 rounded-lg text-sm" > - Dismiss + {t('connectors.manage.dismiss')} @@ -114,6 +115,7 @@ const ManageWorkspace = ({ hideModal = noop, providedSlug = null }) => { export default memo(ManageWorkspace); const ModalTabSwitcher = ({ selectedTab, setSelectedTab }) => { + const { t } = useTranslation(); return (
@@ -125,7 +127,7 @@ const ModalTabSwitcher = ({ selectedTab, setSelectedTab }) => { : "text-white/20 font-medium hover:text-white light:bg-white light:text-[#535862] light:hover:bg-[#E0F2FE]" }`} > - Documents + {t('connectors.manage.documents')}
diff --git a/frontend/src/components/UserMenu/AccountModal/index.jsx b/frontend/src/components/UserMenu/AccountModal/index.jsx index 9de86893486..edbaee590dd 100644 --- a/frontend/src/components/UserMenu/AccountModal/index.jsx +++ b/frontend/src/components/UserMenu/AccountModal/index.jsx @@ -6,6 +6,7 @@ import showToast from "@/utils/toast"; import { Plus, X } from "@phosphor-icons/react"; import ModalWrapper from "@/components/ModalWrapper"; import { useTheme } from "@/hooks/useTheme"; +import { useTranslation } from "react-i18next"; export default function AccountModal({ user, hideModal }) { const { pfp, setPfp } = usePfp(); @@ -28,6 +29,7 @@ export default function AccountModal({ user, hideModal }) { }; const handleRemovePfp = async () => { + const { success, error } = await System.removePfp(); if (!success) { showToast(`Failed to remove profile picture: ${error}`, "error"); @@ -39,7 +41,7 @@ export default function AccountModal({ user, hideModal }) { const handleUpdate = async (e) => { e.preventDefault(); - + const data = {}; const form = new FormData(e.target); for (var [key, value] of form.entries()) { @@ -61,14 +63,14 @@ export default function AccountModal({ user, hideModal }) { showToast(`Failed to update user: ${error}`, "error"); } }; - + const { t } = useTranslation(); return (

- Edit Account + {t('profile_settings.edit_account')}

)}
@@ -129,7 +131,7 @@ export default function AccountModal({ user, hideModal }) { htmlFor="username" className="block mb-2 text-sm font-medium text-theme-text-primary" > - Username + {t('profile_settings.username')}

- Username must be only contain lowercase letters, numbers, - underscores, and hyphens with no spaces + {t('profile_settings.username_description')}

@@ -151,7 +152,7 @@ export default function AccountModal({ user, hideModal }) { htmlFor="password" className="block mb-2 text-sm font-medium text-white" > - New Password + {t('profile_settings.new_password')}

- Password must be at least 8 characters long + {t('profile_settings.passwort_description')}

@@ -175,13 +176,13 @@ export default function AccountModal({ user, hideModal }) { type="button" className="transition-all duration-300 text-white hover:bg-zinc-700 px-4 py-2 rounded-lg text-sm" > - Cancel + {t('profile_settings.cancel')}
@@ -198,14 +199,14 @@ function LanguagePreference() { getLanguageName, changeLanguage, } = useLanguageOptions(); - + const { t } = useTranslation(); return (

- Welcome to your new workspace. + {t('chat_window.welcome')}

{!user || user.role !== "default" ? (

- To get started either{" "} + {t('chat_window.get_started')} - upload a document + {t('chat_window.upload')} - or send a chat. + {t('chat_window.or')} {t('chat_window.send_chat')}

) : (

- To get started send a chat. + {t('chat_window.get_started_default')} {t('chat_window.send_chat')}

)} setShowAgents(!showing)} className={`flex justify-center items-center cursor-pointer ${ showing ? "!opacity-100" : "" diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/AttachItem/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/AttachItem/index.jsx index fcdee57f9a5..b8af609afa5 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/AttachItem/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/AttachItem/index.jsx @@ -1,12 +1,14 @@ import useUser from "@/hooks/useUser"; import { PaperclipHorizontal } from "@phosphor-icons/react"; import { Tooltip } from "react-tooltip"; +import { useTranslation } from "react-i18next"; /** * This is a simple proxy component that clicks on the DnD file uploader for the user. * @returns */ export default function AttachItem() { + const { t } = useTranslation(); const { user } = useUser(); if (!!user && user.role === "default") return null; @@ -15,8 +17,8 @@ export default function AttachItem() {