diff --git a/apps/4tu/package.json b/apps/4tu/package.json index 37e3a6e4..48aebc6f 100644 --- a/apps/4tu/package.json +++ b/apps/4tu/package.json @@ -13,6 +13,7 @@ "@dans-framework/deposit": "workspace:*", "@dans-framework/layout": "workspace:*", "@dans-framework/pages": "workspace:*", + "@dans-framework/repo-advisor": "workspace:*", "@dans-framework/theme": "workspace:*", "@dans-framework/user-auth": "workspace:*", "@dans-framework/utils": "workspace:*", @@ -21,8 +22,12 @@ "framer-motion": "^10.15.0", "lz-string": "^1.5.0", "notistack": "^3.0.1", + "i18next": "^23.4.1", + "i18next-browser-languagedetector": "^7.1.0", + "i18next-resources-to-backend": "^1.1.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-i18next": "^13.0.3", "react-router-dom": "^6.14.2", "use-debounce": "^9.0.4", "web-vitals": "^3.4.0" diff --git a/apps/4tu/src/App.tsx b/apps/4tu/src/App.tsx index cf7d90e8..13d56c29 100644 --- a/apps/4tu/src/App.tsx +++ b/apps/4tu/src/App.tsx @@ -2,8 +2,9 @@ import { Suspense, useState } from "react"; import { BrowserRouter, Routes, Route } from "react-router-dom"; import Skeleton from "@mui/material/Skeleton"; import Box from "@mui/material/Box"; +import { useTranslation } from "react-i18next"; import { ThemeWrapper } from "@dans-framework/theme"; -import { MenuBar, Footer } from "@dans-framework/layout"; +import { LanguageBar, MenuBar, Footer } from "@dans-framework/layout"; import { Deposit, type FormConfig } from "@dans-framework/deposit"; import { AuthWrapper, @@ -12,17 +13,20 @@ import { UserSubmissions, SignInCallback, } from "@dans-framework/user-auth"; -import RepoAdvisor, { NoRepoSelected, CurrentlySelected } from './config/pages/RepoAdvisor'; +import { RepoAdvisor, RepoBar, NoRepoSelected } from '@dans-framework/repo-advisor'; +import { Generic, type Page } from "@dans-framework/pages"; // Load config variables import pages from "./config/pages"; import theme from "./config/theme"; import footer from "./config/footer"; import siteTitle from "./config/siteTitle"; +import languages from "./config/languages"; import authProvider from "./config/auth"; import { AnimatePresence, motion } from "framer-motion"; const App = () => { + const { i18n } = useTranslation(); const [ repoConfig, setRepoConfig ] = useState(); const configIsSet = repoConfig?.hasOwnProperty('form') || false; return ( @@ -35,12 +39,16 @@ const App = () => { initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -10 }} - key={repoConfig?.displayName?.en} + key="repo" > - + } + { > } /> - - - - } - /> { target={repoConfig.targetCredentials} depositSlug="" /> : - + } } @@ -84,11 +84,35 @@ const App = () => { {repoConfig ? : - + } } /> + + {(pages as Page[]).map((page) => { + return ( + + {repoConfig ? + : + + } + + : page.template === "advisor" ? + + + + : + } + /> + ); + })} + { inMenu: true, }} /> : - + } } @@ -112,7 +136,7 @@ const App = () => { path="*" element={ - + } /> diff --git a/apps/4tu/src/config/i18n.ts b/apps/4tu/src/config/i18n.ts new file mode 100644 index 00000000..7ded014b --- /dev/null +++ b/apps/4tu/src/config/i18n.ts @@ -0,0 +1,40 @@ +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; +import languages from "./languages"; +import LanguageDetector from "i18next-browser-languagedetector"; +import { i18n as i18nLayout } from "@dans-framework/layout"; +import { i18n as i18nDeposit } from "@dans-framework/deposit"; +import { i18n as i18nAuth } from "@dans-framework/user-auth"; +import { i18n as i18nRepo } from "@dans-framework/repo-advisor"; + +// this is the main language provider for all subcomponents/libraries +i18n + .use(LanguageDetector) + .use(initReactI18next) + .init({ + debug: import.meta.env.DEV, + supportedLngs: languages, + detection: { + order: ["cookie", "localStorage"], + lookupCookie: "i18next", + lookupLocalStorage: "i18nextLng", + caches: ["localStorage", "cookie"], + }, + fallbackLng: "en", + interpolation: { + escapeValue: false, + }, + react: { + useSuspense: true, + }, + }); + +// make sure to import languages for the components that need it +i18n.on("languageChanged", (lng) => { + i18nLayout.changeLanguage(lng); + i18nDeposit.changeLanguage(lng); + i18nAuth.changeLanguage(lng); + i18nRepo.changeLanguage(lng); +}); + +export default i18n; diff --git a/apps/4tu/src/config/languages.ts b/apps/4tu/src/config/languages.ts new file mode 100644 index 00000000..329d72a2 --- /dev/null +++ b/apps/4tu/src/config/languages.ts @@ -0,0 +1,5 @@ +import type { Language } from "@dans-framework/utils"; + +const languages: Language[] = ["en", "nl"]; + +export default languages; diff --git a/apps/4tu/src/config/pages.ts b/apps/4tu/src/config/pages.ts index 4e9d4ed4..0443c2b2 100644 --- a/apps/4tu/src/config/pages.ts +++ b/apps/4tu/src/config/pages.ts @@ -2,20 +2,32 @@ import type { Page } from "@dans-framework/pages"; const depositPage: Page = { id: "deposit", - name: "Deposit", + name: { + en: "Deposit", + nl: "Deponeren", + }, slug: "deposit", template: "deposit", inMenu: true, - menuTitle: "Deposit", + menuTitle: { + en: "Deposit", + nl: "Deponeren", + }, }; const advisorPage: Page = { id: "advisor", - name: "Advisor", + name: { + en: "Repository selector", + nl: "Repository selector", + }, slug: "/", - template: "deposit", + template: "advisor", inMenu: true, - menuTitle: "Advisor", + menuTitle: { + en: "Repository selector", + nl: "Repository selector", + }, }; export default [ advisorPage, depositPage ]; diff --git a/apps/4tu/src/config/pages/RepoAdvisor.tsx b/apps/4tu/src/config/pages/RepoAdvisor.tsx deleted file mode 100644 index b90ff784..00000000 --- a/apps/4tu/src/config/pages/RepoAdvisor.tsx +++ /dev/null @@ -1,344 +0,0 @@ -import { useState, useEffect, Fragment, type Dispatch, type SetStateAction } from "react"; -import { useNavigate, Link as RouterLink } from "react-router-dom"; -import Stack from '@mui/material/Stack'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; -import Grid from "@mui/material/Unstable_Grid2"; -import Typography from "@mui/material/Typography"; -import Container from "@mui/material/Container"; -import { useDebounce } from "use-debounce"; -import InputLabel from '@mui/material/InputLabel'; -import MenuItem from '@mui/material/MenuItem'; -import FormControl from '@mui/material/FormControl'; -import Select, { SelectChangeEvent } from '@mui/material/Select'; -import TextField from '@mui/material/TextField'; -import Autocomplete from '@mui/material/Autocomplete'; -import type { AutocompleteAPIFieldData, FormConfig } from "@dans-framework/deposit"; -import { AnimatePresence, motion } from "framer-motion"; -import { fetchTypeaheadApiData, postRecommendationsApiData } from "./apiHelpers"; -import { enqueueSnackbar } from "notistack"; -import Link from '@mui/material/Link'; -import List from '@mui/material/List'; -import ListItem from '@mui/material/ListItem'; -import Divider from '@mui/material/Divider'; -import ListItemText from '@mui/material/ListItemText'; - -const RepoAdvisor = ({setRepoConfig}: {setRepoConfig: Dispatch>}) => { - const [recommendations, setRecommendations] = useState(); - const [ror, setRor] = useState