add i18n support and send message/reset chat data attributes

This commit is contained in:
shatfield4
2025-04-23 18:31:49 -07:00
parent 672278fe48
commit 3b0aab94ec
11 changed files with 145 additions and 12 deletions
+8
View File
@@ -61,6 +61,10 @@ REQUIRED data attributes:
- `data-temperature` — Override the chat model temperature. This must be a valid value for your AnythingLLM LLM provider. If unset it will use the embeds attached workspace model temperature or the system setting.
**Language & Localization**
- `data-language` — Set the language for the chat interface. If not specified, it will default to English (en). Currently supported languages: en (English).
**Style Overrides**
- `data-chat-icon` — The chat bubble icon show when chat is closed. Options are `plus`, `chatBubble`, `support`, `search2`, `search`, `magic`.
@@ -97,6 +101,10 @@ REQUIRED data attributes:
- `data-default-messages` - A string of comma-separated messages you want to display to the user when the chat widget has no history. Example: `"How are you?, What is so interesting about this project?, Tell me a joke."`
- `data-send-message-text` — Override the placeholder text in the message input field. If not specified, it will use the translated text based on the selected language.
- `data-reset-chat-text` — Override the text shown on the reset chat button. If not specified, it will use the translated text based on the selected language.
**Behavior Overrides**
- `data-open-on-load` — Once loaded, open the chat as default. It can still be closed by the user. To enable set this attribute to `on`. All other values will be ignored.
+4 -1
View File
@@ -24,7 +24,10 @@
"markdown-it": "^13.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"uuid": "^9.0.1"
"uuid": "^9.0.1",
"i18next": "^23.11.3",
"react-i18next": "^14.1.1",
"i18next-browser-languagedetector": "^7.2.1"
},
"devDependencies": {
"@rollup/plugin-image": "^3.0.3",
+4 -2
View File
@@ -5,6 +5,8 @@ import Head from "@/components/Head";
import OpenButton from "@/components/OpenButton";
import ChatWindow from "./components/ChatWindow";
import { useEffect } from "react";
import { I18nextProvider } from "react-i18next";
import i18next from "@/i18n";
export default function App() {
const { isChatOpen, toggleOpenChat } = useOpenChat();
@@ -31,7 +33,7 @@ export default function App() {
const windowHeight = embedSettings.windowHeight ?? "700px";
return (
<>
<I18nextProvider i18n={i18next}>
<Head />
<div
id="anything-llm-embed-chat-container"
@@ -67,6 +69,6 @@ export default function App() {
/>
</div>
)}
</>
</I18nextProvider>
);
}
@@ -1,5 +1,7 @@
import { CircleNotch, PaperPlaneRight } from "@phosphor-icons/react";
import React, { useState, useRef, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { embedderSettings } from "@/main.jsx";
export default function PromptInput({
message,
@@ -8,6 +10,7 @@ export default function PromptInput({
inputDisabled,
buttonDisabled,
}) {
const { t } = useTranslation();
const formRef = useRef(null);
const textareaRef = useRef(null);
const [_, setFocused] = useState(false);
@@ -71,7 +74,10 @@ export default function PromptInput({
}}
value={message}
className="allm-font-sans allm-border-none allm-cursor-text allm-max-h-[100px] allm-text-[14px] allm-mx-2 allm-py-2 allm-w-full allm-text-black allm-bg-transparent placeholder:allm-text-slate-800/60 allm-resize-none active:allm-outline-none focus:allm-outline-none allm-flex-grow"
placeholder={"Send a message"}
placeholder={
embedderSettings.settings.sendMessageText ||
t("chat.send-message")
}
id="message-input"
/>
<button
+5 -1
View File
@@ -1,6 +1,10 @@
import ChatService from "@/models/chatService";
import { useTranslation } from "react-i18next";
import { embedderSettings } from "@/main.jsx";
export default function ResetChat({ setChatHistory, settings, sessionId }) {
const { t } = useTranslation();
const handleChatReset = async () => {
await ChatService.resetEmbedChatSession(settings, sessionId);
setChatHistory([]);
@@ -13,7 +17,7 @@ export default function ResetChat({ setChatHistory, settings, sessionId }) {
className="hover:allm-cursor-pointer allm-border-none allm-text-sm allm-bg-transparent hover:allm-opacity-80 hover:allm-underline"
onClick={() => handleChatReset()}
>
Reset Chat
{embedderSettings.settings.resetChatText || t("chat.reset-chat")}
</button>
</div>
);
+31
View File
@@ -0,0 +1,31 @@
import i18next from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { defaultNS, resources } from "./locales/resources.js";
export function initI18n(settings) {
const language = settings?.language || "en";
i18next
.use(initReactI18next)
.use(LanguageDetector)
.init({
fallbackLng: "en",
lng: language,
debug: import.meta.env.DEV,
defaultNS,
resources,
load: "languageOnly",
detection: {
order: ["querystring", "navigator"],
lookupQuerystring: "lng",
},
interpolation: {
escapeValue: false,
},
});
return i18next;
}
export default i18next;
+8
View File
@@ -0,0 +1,8 @@
const TRANSLATIONS = {
chat: {
"send-message": "Send a message",
"reset-chat": "Reset Chat",
},
};
export default TRANSLATIONS;
+8
View File
@@ -0,0 +1,8 @@
const TRANSLATIONS = {
chat: {
"send-message": "Envoyer un message",
"reset-chat": "Réinitialiser la conversation",
},
};
export default TRANSLATIONS;
+11
View File
@@ -0,0 +1,11 @@
import English from "./en/common.js";
import French from "./fr/common.js";
export const defaultNS = "common";
export const resources = {
en: {
common: English,
},
fr: {
common: French,
},
};
+13 -7
View File
@@ -3,20 +3,16 @@ import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { parseStylesSrc } from "./utils/constants.js";
const appElement = document.createElement("div");
import { initI18n } from "./i18n.js";
const appElement = document.createElement("div");
document.body.appendChild(appElement);
const root = ReactDOM.createRoot(appElement);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
const scriptSettings = Object.assign(
{},
document?.currentScript?.dataset || {}
);
export const embedderSettings = {
settings: scriptSettings,
stylesSrc: parseStylesSrc(document?.currentScript?.src),
@@ -29,3 +25,13 @@ export const embedderSettings = {
base: `allm-text-[#222628] allm-rounded-t-[18px] allm-rounded-br-[18px] allm-rounded-bl-[4px] allm-mr-[37px] allm-ml-[9px]`,
},
};
// Initialize i18n after settings are available
initI18n(scriptSettings);
const root = ReactDOM.createRoot(appElement);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
+46
View File
@@ -184,6 +184,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9":
version "7.27.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762"
integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==
dependencies:
regenerator-runtime "^0.14.0"
"@babel/template@^7.22.15", "@babel/template@^7.23.9":
version "7.23.9"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.23.9.tgz#f881d0487cba2828d3259dcb9ef5005a9731011a"
@@ -1788,11 +1795,32 @@ highlight.js@^11.9.0:
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0"
integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==
html-parse-stringify@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
dependencies:
void-elements "3.1.0"
human-signals@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
i18next-browser-languagedetector@^7.2.1:
version "7.2.2"
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.2.tgz#748e7dc192847613911d8a79d9d9a6c2d266133e"
integrity sha512-6b7r75uIJDWCcCflmbof+sJ94k9UQO4X0YR62oUfqGI/GjCLVzlCwu8TFdRZIqVLzWbzNcmkmhfqKEr4TLz4HQ==
dependencies:
"@babel/runtime" "^7.23.2"
i18next@^23.11.3:
version "23.16.8"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.16.8.tgz#3ae1373d344c2393f465556f394aba5a9233b93a"
integrity sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==
dependencies:
"@babel/runtime" "^7.23.2"
ignore-by-default@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
@@ -2694,6 +2722,14 @@ react-dom@^18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react-i18next@^14.1.1:
version "14.1.3"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-14.1.3.tgz#85525c4294ef870ddd3f5d184e793cae362f47cb"
integrity sha512-wZnpfunU6UIAiJ+bxwOiTmBOAaB14ha97MjOEnLGac2RJ+h/maIYXZuTHlmyqQVX1UVHmU1YDTQ5vxLmwfXTjw==
dependencies:
"@babel/runtime" "^7.23.9"
html-parse-stringify "^3.0.1"
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@@ -2737,6 +2773,11 @@ reflect.getprototypeof@^1.0.4:
globalthis "^1.0.3"
which-builtin-type "^1.1.3"
regenerator-runtime@^0.14.0:
version "0.14.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e"
@@ -3327,6 +3368,11 @@ vite@^5.0.0:
optionalDependencies:
fsevents "~2.3.3"
void-elements@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
which-boxed-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"