- URL of the website you want to scrape.
+ {t("connectors.website-depth.URL_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..5226e58984e 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() {
{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 fdbef0751f4..82560b433d2 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..2115fb20c2b 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("");
@@ -50,11 +52,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."
- )
- ) {
+ if (!window.confirm(t("connectors.directory.delete-confirmation"))) {
return false;
}
@@ -83,7 +81,10 @@ 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 +167,10 @@ 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 +198,13 @@ function Directory({
-
My Documents
+
+ {t("connectors.directory.my-documents")}
+
@@ -257,7 +263,7 @@ function Directory({
) : (
- No Documents
+ {t("connectors.directory.no-documents")}
)}
@@ -272,7 +278,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")}
) : (
@@ -130,7 +131,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..4a30b86b078 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({
}`}
- *One time cost for embeddings
+ {t("new-workspace.costs")}
@@ -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,26 +280,27 @@ const PinAlert = memo(() => {
weight="regular"
/>
@@ -304,7 +308,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 +317,7 @@ const PinAlert = memo(() => {
});
const DocumentWatchAlert = memo(() => {
+ const { t } = useTranslation();
const [showAlert, setShowAlert] = useState(false);
function dismissAlert() {
setShowAlert(false);
@@ -340,31 +345,29 @@ const DocumentWatchAlert = memo(() => {
weight="regular"
/>
- Edit Account
+ {t("profile_settings.edit_account")}
)}
@@ -129,7 +130,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")}
@@ -189,13 +189,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")}
@@ -212,14 +212,14 @@ function LanguagePreference() {
getLanguageName,
changeLanguage,
} = useLanguageOptions();
-
+ const { t } = useTranslation();
return (