translation in frontend

This commit is contained in:
Felix Kaspar 2024-01-28 19:14:53 +01:00
parent 9a721f8658
commit fbc921a077
9 changed files with 80 additions and 15 deletions

View File

@ -4,6 +4,7 @@ import { Routes, Route, Outlet } from "react-router-dom";
import Home from "./pages/Home"; import Home from "./pages/Home";
import About from "./pages/About"; import About from "./pages/About";
import Dashboard from "./pages/Dashboard"; import Dashboard from "./pages/Dashboard";
import Dynamic from "./pages/Dynamic";
import ToPdf from "./pages/convert/ToPdf"; import ToPdf from "./pages/convert/ToPdf";
import Impose from "./pages/page-operations/Impose"; import Impose from "./pages/page-operations/Impose";
import NoMatch from "./pages/NoMatch"; import NoMatch from "./pages/NoMatch";
@ -15,10 +16,20 @@ import { Container } from "react-bootstrap";
import { useTranslation, initReactI18next } from "react-i18next"; import { useTranslation, initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector"; import LanguageDetector from "i18next-browser-languagedetector";
import i18n, { options } from "@stirling-pdf/shared-operations/src/i18next.config"; import i18next from "i18next";
import resourcesToBackend from "i18next-resources-to-backend";
i18n.use(LanguageDetector) i18next.use(LanguageDetector).use(initReactI18next).use(resourcesToBackend((language: string, namespace: string) => import(`../../shared-operations/public/locales/${namespace}/${language}.json`)))
.use(initReactI18next).init(options) // passes i18n down to react-i18next .init({
debug: true,
ns: ["common"], // Preload this namespace, no need to add the others, they will load once their module is loaded
defaultNS: "common",
fallbackLng: "en",
interpolation: {
escapeValue: false,
},
initImmediate: true // Makes loading blocking but sync
}); // TODO: use i18next.config.ts instead
import "./general.css"; import "./general.css";
@ -34,6 +45,7 @@ export default function App() {
<Route index element={<Home />} /> <Route index element={<Home />} />
<Route path="about" element={<About />} /> <Route path="about" element={<About />} />
<Route path="dashboard" element={<Dashboard />} /> <Route path="dashboard" element={<Dashboard />} />
<Route path="dynamic" element={<Dynamic />} />
{/* Using path="*"" means "match anything", so this route {/* Using path="*"" means "match anything", so this route
acts like a catch-all for URLs that we don't have explicit acts like a catch-all for URLs that we don't have explicit

View File

@ -68,11 +68,13 @@ function convertToNavDropdown(sublist: NavInfoSublist, index: number) {
function NavBar() { function NavBar() {
const { t } = useTranslation(); const { t } = useTranslation();
// TODO: Construct automatically by fetching local & server-side operators
const navInfo = [ const navInfo = [
{displayText: t("multiTool.title"), icon: BsTools, dest: "/home", tooltip: t("home.multiTool.desc")}, {displayText: t("multiTool.title"), icon: BsTools, dest: "/nothing-here", tooltip: t("home.multiTool.desc")},
{displayText: t("navbar.pageOps"), icon: BsFileEarmarkPdf, sublist: [ {displayText: t("navbar.pageOps"), icon: BsFileEarmarkPdf, sublist: [
{ displayText: t("home.merge.title"), icon: AiOutlineMergeCells, dest: "/dashboard", tooltip: t("home.merge.desc") }, { displayText: t("home.merge.title"), icon: AiOutlineMergeCells, dest: "/nothing-here", tooltip: t("home.merge.desc") },
{ displayText: t("home.split.title"), icon: AiOutlineSplitCells, dest: "/about", tooltip: t("home.split.desc") }, { displayText: t("home.split.title"), icon: AiOutlineSplitCells, dest: "/nothing-here", tooltip: t("home.split.desc") },
{ displayText: t("home.pdfOrganiser.title"), icon: BsSortNumericDown, dest: "/nothing-here", tooltip: t("home.pdfOrganiser.desc") }, { displayText: t("home.pdfOrganiser.title"), icon: BsSortNumericDown, dest: "/nothing-here", tooltip: t("home.pdfOrganiser.desc") },
{ displayText: t("home.rotate.title"), icon: BsArrowClockwise, dest: "/nothing-here", tooltip: t("home.rotate.desc") }, { displayText: t("home.rotate.title"), icon: BsArrowClockwise, dest: "/nothing-here", tooltip: t("home.rotate.desc") },
{ displayText: t("home.removePages.title"), icon: BsFileEarmarkX, dest: "/nothing-here", tooltip: t("home.removePages.desc") }, { displayText: t("home.removePages.title"), icon: BsFileEarmarkX, dest: "/nothing-here", tooltip: t("home.removePages.desc") },

View File

@ -1,4 +0,0 @@
declare module "@stirling-pdf/shared-operations/wasm/pdfcpu/pdfcpu-wrapper-browser.js" {
export async function oneToOne(wasmArray: any, snapshot: any): Promise<Uint8Array>;
}

View File

@ -0,0 +1,49 @@
import { Link } from "react-router-dom";
import { listOperatorNames } from "@stirling-pdf/shared-operations/src/workflow/getOperatorByName"
import { Impose } from "@stirling-pdf/shared-operations/src/functions/impose"
import { BaseSyntheticEvent } from "react";
function Dynamic() {
console.log(listOperatorNames());
const operators = listOperatorNames();
function selectionChanged(s: BaseSyntheticEvent) {
const selectedValue = s.target.value;
if(selectedValue == "none") return;
const LoadedOperator = import(`../shared-operations/src/functions/${selectedValue}`);
LoadedOperator.then(console.log);
}
return (
<div>
<h2>Dynamic test page for operators</h2>
<input type="file" id="pdfFile" accept=".pdf" multiple />
<br />
<br />
<textarea name="workflow" id="workflow"></textarea>
<br />
<select id="pdfOptions" onChange={selectionChanged}>
<option value="none">none</option>
{operators.map((operator, i) => {
return (<option value={operator}>{operator}</option>)
})}
</select>
<button id="loadButton">Load</button>
<br />
<br />
<button id="doneButton">Done</button>
<p>
<Link to="/">Go back home...</Link>
</p>
</div>
);
}
export default Dynamic;

View File

@ -1,8 +1,12 @@
import { Link } from "react-router-dom";
function Home() { function Home() {
return ( return (
<div> <div>
<h2>Home</h2> <h2>Home</h2>
<Link to="/about">About</Link><br />
<Link to="/dashboard">Dashboard</Link><br />
<Link to="/dynamic">Dynamic</Link>
</div> </div>
); );
} }

View File

@ -3,9 +3,9 @@ import { Link } from "react-router-dom";
function NoMatch() { function NoMatch() {
return ( return (
<div> <div>
<h2>Nothing to see here!</h2> <h2>The Page you are trying to access does not exist.</h2>
<p> <p>
<Link to="/">Go to the home page 3</Link> <Link to="/">Go back home...</Link>
</p> </p>
</div> </div>
); );

View File

@ -1,4 +1,5 @@
import "@stirling-pdf/shared-operations/src/i18next.config"; import { init } from "@stirling-pdf/shared-operations/src/i18next.config";
init("./public/locales/");
import express from "express"; import express from "express";
const app = express(); const app = express();

View File

@ -27,5 +27,5 @@ export function getOperatorByName(name: string): typeof Operator | undefined {
export function listOperatorNames(): string[] { export function listOperatorNames(): string[] {
// TODO: Implement this // TODO: Implement this
return []; return ["impose"];
} }

View File

@ -1,6 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "Node16", "module": "ESNext",
"moduleResolution": "Bundler",
"esModuleInterop": true, "esModuleInterop": true,
"baseUrl": "./src", /* Specify the base directory to resolve non-relative module names. */ "baseUrl": "./src", /* Specify the base directory to resolve non-relative module names. */
"paths": { "paths": {