Skip to content

Commit

Permalink
Init support of i18n and English, Mandarin, Spanish, French (Mintplex…
Browse files Browse the repository at this point in the history
…-Labs#1317)

* Init support of i18n and English and mandarin

* Update common.js (Mintplex-Labs#1320)

* add General Appearance and Chat setting zh translate (Mintplex-Labs#1414)

* add config zh translate (Mintplex-Labs#1461)

* patch some translation pages

* Update locality fixes

* update: complete login page Mandarin translation. (Mintplex-Labs#1709)

update: complete Mandarin translation.

* complete translation

* update github to run validator

* bump to test workflow failure

* bump to fix tests

* update workflow

* refactor lang selector support

* add Spanish and French

* add dictionaries

---------

Co-authored-by: GetOffer.help <[email protected]>
Co-authored-by: AIR <[email protected]>
Co-authored-by: Ezio T <[email protected]>
  • Loading branch information
4 people authored and sync_forks committed Aug 1, 2024
1 parent ac97cd8 commit 8465aae
Show file tree
Hide file tree
Showing 60 changed files with 2,786 additions and 412 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/check-translations.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This Github action is for validation of all languages which translations are offered for
# in the locales folder in `frontend/src`. All languages are compared to the EN translation
# schema since that is the fallback language setting. This workflow will run on all PRs that
# modify any files in the translation directory
name: Verify translations files

concurrency:
group: build-${{ github.ref }}
cancel-in-progress: true

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- "frontend/src/locales/**.js"

jobs:
run-script:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Run verifyTranslations.mjs script
run: |
cd frontend/src/locales
node verifyTranslations.mjs
- name: Fail job on error
if: failure()
run: exit 1
5 changes: 4 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"file-saver": "^2.0.5",
"he": "^1.2.0",
"highlight.js": "^11.9.0",
"i18next": "^23.11.3",
"i18next-browser-languagedetector": "^7.2.1",
"js-levenshtein": "^1.1.6",
"lodash.debounce": "^4.0.8",
"markdown-it": "^13.0.1",
Expand All @@ -27,6 +29,7 @@
"react-device-detect": "^2.2.2",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
"react-i18next": "^14.1.1",
"react-loading-skeleton": "^3.1.0",
"react-router-dom": "^6.3.0",
"react-speech-recognition": "^3.10.0",
Expand Down Expand Up @@ -64,4 +67,4 @@
"tailwindcss": "^3.3.1",
"vite": "^4.3.0"
}
}
}
210 changes: 108 additions & 102 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { lazy, Suspense } from "react";
import { Routes, Route } from "react-router-dom";
import { I18nextProvider } from "react-i18next";
import { ContextWrapper } from "@/AuthContext";
import PrivateRoute, {
AdminRoute,
Expand All @@ -9,6 +10,7 @@ import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import Login from "@/pages/Login";
import OnboardingFlow from "@/pages/OnboardingFlow";
import i18n from "./i18n";

import { PfpProvider } from "./PfpContext";
import { LogoProvider } from "./LogoContext";
Expand Down Expand Up @@ -61,109 +63,113 @@ export default function App() {
<ContextWrapper>
<LogoProvider>
<PfpProvider>
<Routes>
<Route path="/" element={<PrivateRoute Component={Main} />} />
<Route path="/login" element={<Login />} />
<Route
path="/workspace/:slug/settings/:tab"
element={<ManagerRoute Component={WorkspaceSettings} />}
/>
<Route
path="/workspace/:slug"
element={<PrivateRoute Component={WorkspaceChat} />}
/>
<Route
path="/workspace/:slug/t/:threadSlug"
element={<PrivateRoute Component={WorkspaceChat} />}
/>
<Route path="/accept-invite/:code" element={<InvitePage />} />
<I18nextProvider i18n={i18n}>
<Routes>
<Route path="/" element={<PrivateRoute Component={Main} />} />
<Route path="/login" element={<Login />} />
<Route
path="/workspace/:slug/settings/:tab"
element={<ManagerRoute Component={WorkspaceSettings} />}
/>
<Route
path="/workspace/:slug"
element={<PrivateRoute Component={WorkspaceChat} />}
/>
<Route
path="/workspace/:slug/t/:threadSlug"
element={<PrivateRoute Component={WorkspaceChat} />}
/>
<Route path="/accept-invite/:code" element={<InvitePage />} />

{/* Admin */}
<Route
path="/settings/llm-preference"
element={<AdminRoute Component={GeneralLLMPreference} />}
/>
<Route
path="/settings/transcription-preference"
element={
<AdminRoute Component={GeneralTranscriptionPreference} />
}
/>
<Route
path="/settings/audio-preference"
element={<AdminRoute Component={GeneralAudioPreference} />}
/>
<Route
path="/settings/embedding-preference"
element={<AdminRoute Component={GeneralEmbeddingPreference} />}
/>
<Route
path="/settings/text-splitter-preference"
element={
<AdminRoute Component={EmbeddingTextSplitterPreference} />
}
/>
<Route
path="/settings/vector-database"
element={<AdminRoute Component={GeneralVectorDatabase} />}
/>
<Route
path="/settings/agents"
element={<AdminRoute Component={AdminAgents} />}
/>
<Route
path="/settings/event-logs"
element={<AdminRoute Component={AdminLogs} />}
/>
<Route
path="/settings/embed-config"
element={<AdminRoute Component={EmbedConfigSetup} />}
/>
<Route
path="/settings/embed-chats"
element={<AdminRoute Component={EmbedChats} />}
/>
{/* Manager */}
<Route
path="/settings/security"
element={<ManagerRoute Component={GeneralSecurity} />}
/>
<Route
path="/settings/privacy"
element={<AdminRoute Component={PrivacyAndData} />}
/>
<Route
path="/settings/appearance"
element={<ManagerRoute Component={GeneralAppearance} />}
/>
<Route
path="/settings/api-keys"
element={<AdminRoute Component={GeneralApiKeys} />}
/>
<Route
path="/settings/workspace-chats"
element={<ManagerRoute Component={GeneralChats} />}
/>
<Route
path="/settings/system-preferences"
element={<ManagerRoute Component={AdminSystem} />}
/>
<Route
path="/settings/invites"
element={<ManagerRoute Component={AdminInvites} />}
/>
<Route
path="/settings/users"
element={<ManagerRoute Component={AdminUsers} />}
/>
<Route
path="/settings/workspaces"
element={<ManagerRoute Component={AdminWorkspaces} />}
/>
{/* Onboarding Flow */}
<Route path="/onboarding" element={<OnboardingFlow />} />
<Route path="/onboarding/:step" element={<OnboardingFlow />} />
</Routes>
{/* Admin */}
<Route
path="/settings/llm-preference"
element={<AdminRoute Component={GeneralLLMPreference} />}
/>
<Route
path="/settings/transcription-preference"
element={
<AdminRoute Component={GeneralTranscriptionPreference} />
}
/>
<Route
path="/settings/audio-preference"
element={<AdminRoute Component={GeneralAudioPreference} />}
/>
<Route
path="/settings/embedding-preference"
element={
<AdminRoute Component={GeneralEmbeddingPreference} />
}
/>
<Route
path="/settings/text-splitter-preference"
element={
<AdminRoute Component={EmbeddingTextSplitterPreference} />
}
/>
<Route
path="/settings/vector-database"
element={<AdminRoute Component={GeneralVectorDatabase} />}
/>
<Route
path="/settings/agents"
element={<AdminRoute Component={AdminAgents} />}
/>
<Route
path="/settings/event-logs"
element={<AdminRoute Component={AdminLogs} />}
/>
<Route
path="/settings/embed-config"
element={<AdminRoute Component={EmbedConfigSetup} />}
/>
<Route
path="/settings/embed-chats"
element={<AdminRoute Component={EmbedChats} />}
/>
{/* Manager */}
<Route
path="/settings/security"
element={<ManagerRoute Component={GeneralSecurity} />}
/>
<Route
path="/settings/privacy"
element={<AdminRoute Component={PrivacyAndData} />}
/>
<Route
path="/settings/appearance"
element={<ManagerRoute Component={GeneralAppearance} />}
/>
<Route
path="/settings/api-keys"
element={<AdminRoute Component={GeneralApiKeys} />}
/>
<Route
path="/settings/workspace-chats"
element={<ManagerRoute Component={GeneralChats} />}
/>
<Route
path="/settings/system-preferences"
element={<ManagerRoute Component={AdminSystem} />}
/>
<Route
path="/settings/invites"
element={<ManagerRoute Component={AdminInvites} />}
/>
<Route
path="/settings/users"
element={<ManagerRoute Component={AdminUsers} />}
/>
<Route
path="/settings/workspaces"
element={<ManagerRoute Component={AdminWorkspaces} />}
/>
{/* Onboarding Flow */}
<Route path="/onboarding" element={<OnboardingFlow />} />
<Route path="/onboarding/:step" element={<OnboardingFlow />} />
</Routes>
</I18nextProvider>
<ToastContainer />
</PfpProvider>
</LogoProvider>
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/EditingChatBubble/index.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState } from "react";
import { X } from "@phosphor-icons/react";
import { useTranslation } from "react-i18next";

export default function EditingChatBubble({
message,
Expand All @@ -11,11 +12,12 @@ export default function EditingChatBubble({
const [isEditing, setIsEditing] = useState(false);
const [tempMessage, setTempMessage] = useState(message[type]);
const isUser = type === "user";
const { t } = useTranslation();

return (
<div>
<p className={`text-xs text-[#D3D4D4] ${isUser ? "text-right" : ""}`}>
{isUser ? "User" : "AnythingLLM Chat Assistant"}
{isUser ? t("common.user") : t("appearance.message.assistant")}
</p>
<div
className={`relative flex w-full mt-2 items-start ${
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { useTranslation } from "react-i18next";

export default function NativeEmbeddingOptions() {
const { t } = useTranslation();
return (
<div className="w-full h-10 items-center flex">
<p className="text-sm font-base text-white text-opacity-60">
There is no set up required when using AnythingLLM's native embedding
engine.
{t("embedding.provider.description")}
</p>
</div>
);
Expand Down
18 changes: 12 additions & 6 deletions frontend/src/components/Modals/Password/MultiUserAuth.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import showToast from "@/utils/toast";
import ModalWrapper from "@/components/ModalWrapper";
import { useModal } from "@/hooks/useModal";
import RecoveryCodeModal from "@/components/Modals/DisplayRecoveryCodeModal";
import { useTranslation } from "react-i18next";

const RecoveryForm = ({ onSubmit, setShowRecoveryForm }) => {
const [username, setUsername] = useState("");
Expand Down Expand Up @@ -160,6 +161,7 @@ const ResetPasswordForm = ({ onSubmit }) => {
};

export default function MultiUserAuth() {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [recoveryCodes, setRecoveryCodes] = useState([]);
Expand Down Expand Up @@ -279,14 +281,15 @@ export default function MultiUserAuth() {
<div className="flex items-center flex-col gap-y-4">
<div className="flex gap-x-1">
<h3 className="text-md md:text-2xl font-bold text-white text-center white-space-nowrap hidden md:block">
Welcome to
{t("login.multi-user.welcome")}
</h3>
<p className="text-4xl md:text-2xl font-bold bg-gradient-to-r from-[#75D6FF] via-[#FFFFFF] to-[#FFFFFF] bg-clip-text text-transparent">
{customAppName || "AnythingLLM"}
</p>
</div>
<p className="text-sm text-white/90 text-center">
Sign in to your {customAppName || "AnythingLLM"} account.
{t("login.sign-in.start")} {customAppName || "AnythingLLM"}{" "}
{t("login.sign-in.end")}
</p>
</div>
</div>
Expand All @@ -296,7 +299,7 @@ export default function MultiUserAuth() {
<input
name="username"
type="text"
placeholder="Username"
placeholder={t("login.multi-user.placeholder-username")}
className="bg-zinc-900 text-white placeholder-white/20 text-sm rounded-md p-2.5 w-full h-[48px] md:w-[300px] md:h-[34px]"
required={true}
autoComplete="off"
Expand All @@ -306,7 +309,7 @@ export default function MultiUserAuth() {
<input
name="password"
type="password"
placeholder="Password"
placeholder={t("login.multi-user.placeholder-password")}
className="bg-zinc-900 text-white placeholder-white/20 text-sm rounded-md p-2.5 w-full h-[48px] md:w-[300px] md:h-[34px]"
required={true}
autoComplete="off"
Expand All @@ -321,14 +324,17 @@ export default function MultiUserAuth() {
type="submit"
className="md:text-primary-button md:bg-transparent text-dark-text text-sm font-bold focus:ring-4 focus:outline-none rounded-md border-[1.5px] border-[#46C8FF] md:h-[34px] h-[48px] md:hover:text-white md:hover:bg-primary-button bg-primary-button focus:z-10 w-full"
>
{loading ? "Validating..." : "Login"}
{loading
? t("login.multi-user.validating")
: t("login.multi-user.login")}
</button>
<button
type="button"
className="text-white text-sm flex gap-x-1 hover:text-primary-button hover:underline"
onClick={handleResetPassword}
>
Forgot password?<b>Reset</b>
{t("login.multi-user.forgot-pass")}?
<b>{t("login.multi-user.reset")}</b>
</button>
</div>
</div>
Expand Down
Loading

0 comments on commit 8465aae

Please sign in to comment.