- Controller networks
- {networks[0] && "Network controller address"}
+ {t("controllerNetworks")}
+ {networks[0] && t("controllerAddress")}
- {networks[0] && networks[0]["id"].slice(0, 10)}
+ {networks[0] && String(networks[0]["id"]).slice(0, 10)}
- Networks
+ {t("network", { count: networks.length })}
{networks[0] ? (
networks.map((network) => (
@@ -59,7 +63,7 @@ function HomeLoggedIn() {
))
) : (
- Please create at least one network
+ {t("createOneNetwork")}
)}
diff --git a/frontend/src/components/HomeLoggedIn/index.jsx b/frontend/src/components/HomeLoggedIn/index.jsx
index 5e81fc49..e532a122 100644
--- a/frontend/src/components/HomeLoggedIn/index.jsx
+++ b/frontend/src/components/HomeLoggedIn/index.jsx
@@ -1 +1 @@
-export { default } from "./HomeLoggedIn";
+export { default } from "./HomeLoggedIn.jsx";
diff --git a/frontend/src/components/HomeLoggedOut/HomeLoggedOut.jsx b/frontend/src/components/HomeLoggedOut/HomeLoggedOut.jsx
index 0de5572d..7ec32181 100644
--- a/frontend/src/components/HomeLoggedOut/HomeLoggedOut.jsx
+++ b/frontend/src/components/HomeLoggedOut/HomeLoggedOut.jsx
@@ -3,6 +3,8 @@ import { Grid, Typography } from "@material-ui/core";
import { useLocalStorage } from "react-use";
import { useHistory } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+
import axios from "axios";
function HomeLoggedOut() {
@@ -29,6 +31,8 @@ function HomeLoggedOut() {
fetchData();
}, [history, setDisableAuth, setLoggedIn, setToken]);
+ const { t, i18n } = useTranslation();
+
return (
-
- ZeroUI - ZeroTier Controller Web UI - is a web user interface for a
- self-hosted ZeroTier network controller.
-
+ {t("zerouiDesc")}
- Please Log In to continue
+ {t("loginToContinue")}
diff --git a/frontend/src/components/HomeLoggedOut/index.jsx b/frontend/src/components/HomeLoggedOut/index.jsx
index bfd68924..094d9825 100644
--- a/frontend/src/components/HomeLoggedOut/index.jsx
+++ b/frontend/src/components/HomeLoggedOut/index.jsx
@@ -1 +1 @@
-export { default } from "./HomeLoggedOut";
+export { default } from "./HomeLoggedOut.jsx";
diff --git a/frontend/src/components/LogIn/LogIn.jsx b/frontend/src/components/LogIn/LogIn.jsx
index 36ea9a29..73e06336 100644
--- a/frontend/src/components/LogIn/LogIn.jsx
+++ b/frontend/src/components/LogIn/LogIn.jsx
@@ -1,7 +1,7 @@
import { Divider } from "@material-ui/core";
-import LogInUser from "./components/LogInUser";
-import LogInToken from "./components/LogInToken";
+import LogInUser from "./components/LogInUser/LogInUser.jsx";
+import LogInToken from "./components/LogInToken/LogInToken.jsx";
function LogIn() {
return (
@@ -12,6 +12,7 @@ function LogIn() {
>
)}
+
>
);
diff --git a/frontend/src/components/LogIn/components/LogInToken/LogInToken.jsx b/frontend/src/components/LogIn/components/LogInToken/LogInToken.jsx
index a4140755..b39b4156 100644
--- a/frontend/src/components/LogIn/components/LogInToken/LogInToken.jsx
+++ b/frontend/src/components/LogIn/components/LogInToken/LogInToken.jsx
@@ -12,6 +12,8 @@ import {
DialogTitle,
} from "@material-ui/core";
+import { useTranslation } from "react-i18next";
+
function LogInToken() {
const [open, setOpen] = useState(false);
const [errorText, setErrorText] = useState("");
@@ -41,6 +43,8 @@ function LogInToken() {
}
};
+ const { t, i18n } = useTranslation();
+
const LogIn = () => {
if (token.length !== 32) {
setErrorText("Token length error");
@@ -55,12 +59,12 @@ function LogInToken() {
return (
diff --git a/frontend/src/components/LogIn/components/LogInToken/index.jsx b/frontend/src/components/LogIn/components/LogInToken/index.jsx
index 32428b0d..eccdd52a 100644
--- a/frontend/src/components/LogIn/components/LogInToken/index.jsx
+++ b/frontend/src/components/LogIn/components/LogInToken/index.jsx
@@ -1 +1 @@
-export { default } from "./LogInToken";
+export { default } from "./LogInToken.jsx";
diff --git a/frontend/src/components/LogIn/components/LogInUser/LogInUser.jsx b/frontend/src/components/LogIn/components/LogInUser/LogInUser.jsx
index 0658d3c3..d6d1af0f 100644
--- a/frontend/src/components/LogIn/components/LogInUser/LogInUser.jsx
+++ b/frontend/src/components/LogIn/components/LogInUser/LogInUser.jsx
@@ -13,6 +13,8 @@ import {
import axios from "axios";
+import { useTranslation } from "react-i18next";
+
function LogInUser() {
const [open, setOpen] = useState(false);
const [snackbarOpen, setSnackbarOpen] = useState(false);
@@ -72,13 +74,15 @@ function LogInUser() {
});
};
+ const { t, i18n } = useTranslation();
+
return (
<>
@@ -117,7 +121,7 @@ function LogInUser() {
vertical: "top",
horizontal: "center",
}}
- message={error}
+ message={t(error)}
/>
>
);
diff --git a/frontend/src/components/LogIn/components/LogInUser/index.jsx b/frontend/src/components/LogIn/components/LogInUser/index.jsx
index 92fb0ca3..202ce94d 100644
--- a/frontend/src/components/LogIn/components/LogInUser/index.jsx
+++ b/frontend/src/components/LogIn/components/LogInUser/index.jsx
@@ -1 +1 @@
-export { default } from "./LogInUser";
+export { default } from "./LogInUser.jsx";
diff --git a/frontend/src/components/LogIn/index.jsx b/frontend/src/components/LogIn/index.jsx
index 7b22dd87..016d22cf 100644
--- a/frontend/src/components/LogIn/index.jsx
+++ b/frontend/src/components/LogIn/index.jsx
@@ -1 +1 @@
-export { default } from "./LogIn";
+export { default } from "./LogIn.jsx";
diff --git a/frontend/src/components/NetworkHeader/index.jsx b/frontend/src/components/NetworkHeader/index.jsx
index 788a9750..1927b0ce 100644
--- a/frontend/src/components/NetworkHeader/index.jsx
+++ b/frontend/src/components/NetworkHeader/index.jsx
@@ -1 +1 @@
-export { default } from "./NetworkHeader";
+export { default } from "./NetworkHeader.jsx";
diff --git a/frontend/src/components/NetworkManagement/NetworkManagement.jsx b/frontend/src/components/NetworkManagement/NetworkManagement.jsx
index fab98cce..152ef203 100644
--- a/frontend/src/components/NetworkManagement/NetworkManagement.jsx
+++ b/frontend/src/components/NetworkManagement/NetworkManagement.jsx
@@ -13,10 +13,12 @@ import {
DialogActions,
Typography,
} from "@material-ui/core";
-import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
-import DeleteIcon from "@material-ui/icons/Delete";
+import ExpandMoreIcon from "@material-ui/icons/ExpandMore.js";
+import DeleteIcon from "@material-ui/icons/Delete.js";
-import API from "utils/API";
+import API from "utils/API.js";
+
+import { useTranslation } from "react-i18next";
function NetworkManagement() {
const { nwid } = useParams();
@@ -42,10 +44,12 @@ function NetworkManagement() {
history.go(0);
};
+ const { t, i18n } = useTranslation();
+
return (
}>
- Management
+ {t("management")}
}
onClick={handleClickOpen}
>
- Delete Network
+ {t("deleteNetwork")}
diff --git a/frontend/src/components/NetworkManagement/index.jsx b/frontend/src/components/NetworkManagement/index.jsx
index 281dbc95..d54147da 100644
--- a/frontend/src/components/NetworkManagement/index.jsx
+++ b/frontend/src/components/NetworkManagement/index.jsx
@@ -1 +1 @@
-export { default } from "./NetworkManagement";
+export { default } from "./NetworkManagement.jsx";
diff --git a/frontend/src/components/NetworkMembers/NetworkMembers.jsx b/frontend/src/components/NetworkMembers/NetworkMembers.jsx
index b6f843c8..90ce7e51 100644
--- a/frontend/src/components/NetworkMembers/NetworkMembers.jsx
+++ b/frontend/src/components/NetworkMembers/NetworkMembers.jsx
@@ -7,19 +7,21 @@ import {
IconButton,
Typography,
} from "@material-ui/core";
-import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
-import RefreshIcon from "@material-ui/icons/Refresh";
+import ExpandMoreIcon from "@material-ui/icons/ExpandMore.js";
+import RefreshIcon from "@material-ui/icons/Refresh.js";
import { useCallback, useEffect, useState } from "react";
import DataTable from "react-data-table-component";
import { useParams } from "react-router-dom";
-import API from "utils/API";
-import { parseValue, replaceValue, setValue } from "utils/ChangeHelper";
+import API from "utils/API.js";
+import { parseValue, replaceValue, setValue } from "utils/ChangeHelper.js";
import { formatDistance } from "date-fns";
-import AddMember from "./components/AddMember";
-import DeleteMember from "./components/DeleteMember";
-import ManagedIP from "./components/ManagedIP";
-import MemberName from "./components/MemberName";
-import MemberSettings from "./components/MemberSettings";
+import AddMember from "./components/AddMember/AddMember.jsx";
+import DeleteMember from "./components/DeleteMember/DeleteMember.jsx";
+import ManagedIP from "./components/ManagedIP/ManagedIP.jsx";
+import MemberName from "./components/MemberName/MemberName.jsx";
+import MemberSettings from "./components/MemberSettings/MemberSettings.jsx";
+
+import { useTranslation } from "react-i18next";
function NetworkMembers({ network }) {
const { nwid } = useParams();
@@ -46,6 +48,8 @@ function NetworkMembers({ network }) {
console.log("Action:", req);
};
+ const { t, i18n } = useTranslation();
+
const handleChange =
(member, key1, key2 = null, mode = "text", id = null) =>
(event) => {
@@ -67,7 +71,7 @@ function NetworkMembers({ network }) {
const columns = [
{
id: "auth",
- name: "Authorized",
+ name: t("authorized"),
minWidth: "80px",
cell: (row) => (
(
{row.config.address}
@@ -87,19 +91,19 @@ function NetworkMembers({ network }) {
},
{
id: "name",
- name: "Name / Description",
+ name: t("name") + "/" + t("description"),
minWidth: "250px",
cell: (row) => ,
},
{
id: "ips",
- name: "Managed IPs",
+ name: t("ips"),
minWidth: "220px",
cell: (row) => ,
},
{
id: "status",
- name: "Last Seen",
+ name: t("status"),
minWidth: "100px",
cell: (row) =>
row.online === 1 ? (
@@ -121,7 +125,7 @@ function NetworkMembers({ network }) {
},
{
id: "physicalip",
- name: "Version / Physical IP / Latency",
+ name: t("version") + " / " + t("physIp") + " / " + t("latency"),
minWidth: "220px",
cell: (row) =>
row.online === 1 ? (
@@ -143,7 +147,7 @@ function NetworkMembers({ network }) {
},
{
id: "delete",
- name: "",
+ name: t("settings"),
minWidth: "50px",
right: true,
cell: (row) => (
@@ -162,7 +166,7 @@ function NetworkMembers({ network }) {
return (
}>
- Members
+ {t("member", { count: members.length })}
@@ -188,8 +192,7 @@ function NetworkMembers({ network }) {
}}
>
- No devices have joined this network. Use the app on your
- devices to join {nwid}.
+ {t("noDevices")} {nwid}.
)}
diff --git a/frontend/src/components/NetworkMembers/components/AddMember/AddMember.jsx b/frontend/src/components/NetworkMembers/components/AddMember/AddMember.jsx
index af256d63..862cfda4 100644
--- a/frontend/src/components/NetworkMembers/components/AddMember/AddMember.jsx
+++ b/frontend/src/components/NetworkMembers/components/AddMember/AddMember.jsx
@@ -1,9 +1,11 @@
import { useState } from "react";
import { List, Typography, IconButton, TextField } from "@material-ui/core";
-import AddIcon from "@material-ui/icons/Add";
+import AddIcon from "@material-ui/icons/Add.js";
-import API from "utils/API";
+import API from "utils/API.js";
+
+import { useTranslation } from "react-i18next";
function AddMember({ nwid, callback }) {
const [member, setMember] = useState("");
@@ -24,9 +26,11 @@ function AddMember({ nwid, callback }) {
setMember("");
};
+ const { t, i18n } = useTranslation();
+
return (
<>
- Manually Add Member
+ {t("addMemberMan")}
{
@@ -37,18 +39,16 @@ function DeleteMember({ nwid, mid, callback }) {
diff --git a/frontend/src/components/NetworkMembers/components/DeleteMember/index.jsx b/frontend/src/components/NetworkMembers/components/DeleteMember/index.jsx
index f9e57f41..cc788a32 100644
--- a/frontend/src/components/NetworkMembers/components/DeleteMember/index.jsx
+++ b/frontend/src/components/NetworkMembers/components/DeleteMember/index.jsx
@@ -1 +1 @@
-export { default } from "./DeleteMember";
+export { default } from "./DeleteMember.jsx";
diff --git a/frontend/src/components/NetworkMembers/components/ManagedIP/ManagedIP.jsx b/frontend/src/components/NetworkMembers/components/ManagedIP/ManagedIP.jsx
index f01bbac2..5ed11c82 100644
--- a/frontend/src/components/NetworkMembers/components/ManagedIP/ManagedIP.jsx
+++ b/frontend/src/components/NetworkMembers/components/ManagedIP/ManagedIP.jsx
@@ -1,10 +1,10 @@
import { useState } from "react";
import { Grid, List, TextField, IconButton } from "@material-ui/core";
-import AddIcon from "@material-ui/icons/Add";
-import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
+import AddIcon from "@material-ui/icons/Add.js";
+import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline.js";
-import { validateIP, normilizeIP } from "utils/IP";
+import { validateIP, normilizeIP } from "utils/IP.js";
function ManagedIP({ member, handleChange }) {
const [ipInput, setIpInput] = useState();
diff --git a/frontend/src/components/NetworkMembers/components/ManagedIP/index.jsx b/frontend/src/components/NetworkMembers/components/ManagedIP/index.jsx
index 87fede3e..a412c544 100644
--- a/frontend/src/components/NetworkMembers/components/ManagedIP/index.jsx
+++ b/frontend/src/components/NetworkMembers/components/ManagedIP/index.jsx
@@ -1 +1 @@
-export { default } from "./ManagedIP";
+export { default } from "./ManagedIP.jsx";
diff --git a/frontend/src/components/NetworkMembers/components/MemberName/MemberName.jsx b/frontend/src/components/NetworkMembers/components/MemberName/MemberName.jsx
index 65032cc0..ea7f8e9d 100644
--- a/frontend/src/components/NetworkMembers/components/MemberName/MemberName.jsx
+++ b/frontend/src/components/NetworkMembers/components/MemberName/MemberName.jsx
@@ -1,12 +1,14 @@
import { Grid, TextField } from "@material-ui/core";
+import { useTranslation } from "react-i18next";
function MemberName({ member, handleChange }) {
+ const { t, i18n } = useTranslation();
return (
{
@@ -43,7 +46,7 @@ function MemberSettings({ member, network, handleChange }) {
"checkbox"
)}
/>
- Allow Ethernet Bridging
+ {t("allowBridging")}
- Do Not Auto-Assign IPs
+ {t("noAutoIP")}
- Capabilities
+ {t("capabilities")}
{Object.entries(network["capabilitiesByName"] || []).length ===
0
- ? "No capabilities defined"
+ ? t("noCapDef")
: ""}
{Object.entries(network["capabilitiesByName"] || []).map(
([capName, capId]) => (
@@ -96,11 +99,11 @@ function MemberSettings({ member, network, handleChange }) {
- Tags
+ {t("tags")}
{Object.entries(network["tagsByName"] || []).length === 0 ? (
- No tags defined
+ {t("noTagDef")}
) : (
""
diff --git a/frontend/src/components/NetworkMembers/components/MemberSettings/components/Tag/Tag.jsx b/frontend/src/components/NetworkMembers/components/MemberSettings/components/Tag/Tag.jsx
index 25f257b2..ba252b65 100644
--- a/frontend/src/components/NetworkMembers/components/MemberSettings/components/Tag/Tag.jsx
+++ b/frontend/src/components/NetworkMembers/components/MemberSettings/components/Tag/Tag.jsx
@@ -8,7 +8,7 @@ import {
Select,
Typography,
} from "@material-ui/core";
-import DeleteIcon from "@material-ui/icons/Delete";
+import DeleteIcon from "@material-ui/icons/Delete.js";
import { useEffect, useState } from "react";
import { useDebounce } from "react-use";
diff --git a/frontend/src/components/NetworkMembers/components/MemberSettings/components/Tag/index.jsx b/frontend/src/components/NetworkMembers/components/MemberSettings/components/Tag/index.jsx
index 21bb058a..0547fafc 100644
--- a/frontend/src/components/NetworkMembers/components/MemberSettings/components/Tag/index.jsx
+++ b/frontend/src/components/NetworkMembers/components/MemberSettings/components/Tag/index.jsx
@@ -1 +1 @@
-export { default } from "./Tag";
+export { default } from "./Tag.jsx";
diff --git a/frontend/src/components/NetworkMembers/components/MemberSettings/index.jsx b/frontend/src/components/NetworkMembers/components/MemberSettings/index.jsx
index 2ded616e..7611c65c 100644
--- a/frontend/src/components/NetworkMembers/components/MemberSettings/index.jsx
+++ b/frontend/src/components/NetworkMembers/components/MemberSettings/index.jsx
@@ -1 +1 @@
-export { default } from "./MemberSettings";
+export { default } from "./MemberSettings.jsx";
diff --git a/frontend/src/components/NetworkMembers/index.jsx b/frontend/src/components/NetworkMembers/index.jsx
index 9a38809d..e7f7d4c6 100644
--- a/frontend/src/components/NetworkMembers/index.jsx
+++ b/frontend/src/components/NetworkMembers/index.jsx
@@ -1 +1 @@
-export { default } from "./NetworkMembers";
+export { default } from "./NetworkMembers.jsx";
diff --git a/frontend/src/components/NetworkRules/NetworkRules.jsx b/frontend/src/components/NetworkRules/NetworkRules.jsx
index 14dbd365..d4fea9e0 100644
--- a/frontend/src/components/NetworkRules/NetworkRules.jsx
+++ b/frontend/src/components/NetworkRules/NetworkRules.jsx
@@ -9,15 +9,19 @@ import {
Snackbar,
Typography,
} from "@material-ui/core";
-import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
+import ExpandMoreIcon from "@material-ui/icons/ExpandMore.js";
import CodeMirror from "@uiw/react-codemirror";
import "codemirror/theme/3024-day.css";
-import { compile } from "external/RuleCompiler";
-import debounce from "lodash/debounce";
+import { compile } from "external/RuleCompiler.js";
+import debounce from "lodash/debounce.js";
import { useState } from "react";
-import API from "utils/API";
+import API from "utils/API.js";
+
+import { useTranslation, Trans } from "react-i18next";
function NetworkRules({ network, callback }) {
+ const { t, i18n } = useTranslation();
+
const [editor, setEditor] = useState(null);
const [flowData, setFlowData] = useState({
rules: [...network.config.rules],
@@ -87,12 +91,12 @@ function NetworkRules({ network, callback }) {
return (
}>
- Flow Rules
+ {t("flowRules")}
{/* Important note: value in CodeMirror instance means INITAIL VALUE
or it could be used to replace editor state with the new value.
- No need to update on every user character input
+ No need to update on every user character input Flow Rules
*/}
{
try {
const req = await API.post("/network/" + network["config"]["id"], data);
@@ -43,12 +46,12 @@ function NetworkSettings({ network, setNetwork }) {
return (
}>
- General settings
+ {t("generalSettings")}
- Network ID
+ {t("netId")}
{network["config"]["id"]}
@@ -57,7 +60,7 @@ function NetworkSettings({ network, setNetwork }) {
- Access Control
+ {t("accessControl")}
@@ -111,7 +114,7 @@ function NetworkSettings({ network, setNetwork }) {
- Enable Broadcast
+ {t("enaBroadcast")}
{/* TODO: */}
{/*
diff --git a/frontend/src/components/NetworkSettings/components/IPv4AutoAssign/IPv4AutoAssign.jsx b/frontend/src/components/NetworkSettings/components/IPv4AutoAssign/IPv4AutoAssign.jsx
index 0b4fd3de..34d6b9d7 100644
--- a/frontend/src/components/NetworkSettings/components/IPv4AutoAssign/IPv4AutoAssign.jsx
+++ b/frontend/src/components/NetworkSettings/components/IPv4AutoAssign/IPv4AutoAssign.jsx
@@ -10,15 +10,18 @@ import {
TextField,
IconButton,
} from "@material-ui/core";
-import AddIcon from "@material-ui/icons/Add";
-import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
+import AddIcon from "@material-ui/icons/Add.js";
+import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline.js";
import DataTable from "react-data-table-component";
-import { addressPool } from "utils/NetworkConfig";
-import { getCIDRAddress, validateIP, normilizeIP } from "utils/IP";
+import { addressPool } from "utils/NetworkConfig.js";
+import { getCIDRAddress, validateIP, normilizeIP } from "utils/IP.js";
+
+import { useTranslation } from "react-i18next";
function IPv4AutoAssign({ ipAssignmentPools, handleChange }) {
+ const { t, i18n } = useTranslation();
const [start, setStart] = useState("");
const [end, setEnd] = useState("");
@@ -89,19 +92,19 @@ function IPv4AutoAssign({ ipAssignmentPools, handleChange }) {
},
{
id: "Start",
- name: "Start",
+ name: t("start"),
cell: (row) => row["ipRangeStart"],
},
{
id: "End",
- name: "End",
+ name: t("end"),
cell: (row) => row["ipRangeEnd"],
},
];
return (
<>
- IPv4 Auto-Assign
+ {t("ipv4AutoAssign")}
- Auto-Assign Pools
+ {t("autoAssignPool")}
@@ -132,7 +135,7 @@ function IPv4AutoAssign({ ipAssignmentPools, handleChange }) {
data={ipAssignmentPools}
/>
- Add IPv4 Pool
+ {t("addIPv4Pool")}
(event) => {
+ i18n.changeLanguage(event.target.value);
+ };
+
+ return (
+
+ }>
+ {t("language")}
+
+
+
+
+
+
+
+ );
+}
+
+export default SettingsComponent;
diff --git a/frontend/src/components/SettingsComponent/index.jsx b/frontend/src/components/SettingsComponent/index.jsx
new file mode 100644
index 00000000..57f5ff7a
--- /dev/null
+++ b/frontend/src/components/SettingsComponent/index.jsx
@@ -0,0 +1 @@
+export { default } from "./SettingsComponent.jsx";
diff --git a/frontend/src/components/Theme/index.jsx b/frontend/src/components/Theme/index.jsx
index 3bef82bc..da839bbb 100644
--- a/frontend/src/components/Theme/index.jsx
+++ b/frontend/src/components/Theme/index.jsx
@@ -1 +1 @@
-export { default } from "./Theme";
+export { default } from "./Theme.jsx";
diff --git a/frontend/src/i18n.js b/frontend/src/i18n.js
new file mode 100644
index 00000000..a74ac101
--- /dev/null
+++ b/frontend/src/i18n.js
@@ -0,0 +1,34 @@
+import i18n from "i18next";
+import languageDetector from "i18next-browser-languagedetector";
+import { initReactI18next } from "react-i18next";
+import Backend from "i18next-http-backend";
+
+i18n
+ .use(languageDetector)
+ .use(initReactI18next)
+ .use(Backend)
+ .init({
+ compatibilityJSON: "v4",
+ //lng: "en",
+ fallbackLng: "en",
+ detection: {
+ order: ["path", "cookie", "localStorage", "htmlTag"],
+ caches: ["localStorage", "cookie"], // cache user language on
+ },
+ debug: true,
+ //keySeparator: false, // we use content as keys
+ interpolation: {
+ escapeValue: true,
+ },
+ react: {
+ useSuspense: true,
+ },
+ supportedLngs: ["en", "es-ES"],
+ backend: {
+ loadPath: "/locales/{{lng}}/{{ns}}.json",
+ },
+ ns: ["common"],
+ defaultNS: "common",
+ });
+
+export default i18n;
diff --git a/frontend/src/index.jsx b/frontend/src/index.jsx
index 3c94589b..663c7c09 100644
--- a/frontend/src/index.jsx
+++ b/frontend/src/index.jsx
@@ -1,13 +1,17 @@
import "./index.css";
-import React from "react";
+import React, { Suspense } from "react";
import ReactDOM from "react-dom";
-import App from "./App";
+import App from "./App.jsx";
+
+import "./i18n";
ReactDOM.render(
-
+ Loading...
}>
+
+
,
document.getElementById("root")
);
diff --git a/frontend/src/routes/Home/Home.jsx b/frontend/src/routes/Home/Home.jsx
index faf15a9e..cacdbaad 100644
--- a/frontend/src/routes/Home/Home.jsx
+++ b/frontend/src/routes/Home/Home.jsx
@@ -1,7 +1,7 @@
import { useLocalStorage } from "react-use";
-import HomeLoggedIn from "components/HomeLoggedIn";
-import HomeLoggedOut from "components/HomeLoggedOut";
+import HomeLoggedIn from "components/HomeLoggedIn/HomeLoggedIn.jsx";
+import HomeLoggedOut from "components/HomeLoggedOut/HomeLoggedOut.jsx";
function Home() {
const [loggedIn] = useLocalStorage("loggedIn", false);
diff --git a/frontend/src/routes/Home/index.jsx b/frontend/src/routes/Home/index.jsx
index ffa79319..508ea772 100644
--- a/frontend/src/routes/Home/index.jsx
+++ b/frontend/src/routes/Home/index.jsx
@@ -1 +1 @@
-export { default } from "./Home";
+export { default } from "./Home.jsx";
diff --git a/frontend/src/routes/Network/Network.jsx b/frontend/src/routes/Network/Network.jsx
index 272ba2ad..d5833cc5 100644
--- a/frontend/src/routes/Network/Network.jsx
+++ b/frontend/src/routes/Network/Network.jsx
@@ -1,15 +1,15 @@
import { Grid, Link, Typography } from "@material-ui/core";
-import ArrowBackIcon from "@material-ui/icons/ArrowBack";
-import NetworkHeader from "components/NetworkHeader";
-import NetworkManagement from "components/NetworkManagement";
-import NetworkMembers from "components/NetworkMembers";
-import NetworkRules from "components/NetworkRules";
-import NetworkSettings from "components/NetworkSettings";
+import ArrowBackIcon from "@material-ui/icons/ArrowBack.js";
+import NetworkHeader from "components/NetworkHeader/NetworkHeader.jsx";
+import NetworkManagement from "components/NetworkManagement/NetworkManagement.jsx";
+import NetworkMembers from "components/NetworkMembers/NetworkMembers.jsx";
+import NetworkRules from "components/NetworkRules/NetworkRules.jsx";
+import NetworkSettings from "components/NetworkSettings/NetworkSettings.jsx";
import { useCallback, useEffect, useState } from "react";
import { Link as RouterLink, useHistory, useParams } from "react-router-dom";
import { useLocalStorage } from "react-use";
-import API from "utils/API";
-import useStyles from "./Network.styles";
+import API from "utils/API.js";
+import useStyles from "./Network.styles.jsx";
function Network() {
const { nwid } = useParams();
diff --git a/frontend/src/routes/Network/index.jsx b/frontend/src/routes/Network/index.jsx
index 7a8a2ce1..5d9b2916 100644
--- a/frontend/src/routes/Network/index.jsx
+++ b/frontend/src/routes/Network/index.jsx
@@ -1 +1 @@
-export { default } from "./Network";
+export { default } from "./Network.jsx";
diff --git a/frontend/src/routes/NotFound/index.jsx b/frontend/src/routes/NotFound/index.jsx
index 3fded62c..76e87478 100644
--- a/frontend/src/routes/NotFound/index.jsx
+++ b/frontend/src/routes/NotFound/index.jsx
@@ -1 +1 @@
-export { default } from "./NotFound";
+export { default } from "./NotFound.jsx";
diff --git a/frontend/src/routes/Settings/Settings.jsx b/frontend/src/routes/Settings/Settings.jsx
new file mode 100644
index 00000000..08539ebe
--- /dev/null
+++ b/frontend/src/routes/Settings/Settings.jsx
@@ -0,0 +1,57 @@
+import { Grid, Link, Typography } from "@material-ui/core";
+import ArrowBackIcon from "@material-ui/icons/ArrowBack.js";
+import SettingsComponent from "components/SettingsComponent/SettingsComponent.jsx";
+
+import { useCallback, useEffect, useState } from "react";
+import { Link as RouterLink, useHistory, useParams } from "react-router-dom";
+import { useLocalStorage } from "react-use";
+import API from "utils/API";
+import useStyles from "./Settings.styles.jsx";
+
+import { useTranslation } from "react-i18next";
+
+function Settings() {
+ const { t, i18n } = useTranslation();
+ const [loggedIn] = useLocalStorage("loggedIn", false);
+ const [network, setNetwork] = useState({});
+
+ const classes = useStyles();
+ const history = useHistory();
+
+ if (loggedIn) {
+ return (
+ <>
+
+
+
+ {t("settings")}
+
+
+
+
+
+ >
+ );
+ } else {
+ return (
+
+
+
+ You are not authorized. Please Log In
+
+
+
+ );
+ }
+}
+
+export default Settings;
diff --git a/frontend/src/routes/Settings/Settings.styles.jsx b/frontend/src/routes/Settings/Settings.styles.jsx
new file mode 100644
index 00000000..ac884a75
--- /dev/null
+++ b/frontend/src/routes/Settings/Settings.styles.jsx
@@ -0,0 +1,16 @@
+import { makeStyles } from "@material-ui/core/styles";
+
+const useStyles = makeStyles((theme) => ({
+ backIcon: {
+ fontSize: 12,
+ },
+ container: {
+ margin: "3%",
+ },
+ breadcrumbs: {
+ paddingTop: "2%",
+ paddingLeft: "2%",
+ },
+}));
+
+export default useStyles;
diff --git a/frontend/src/routes/Settings/index.jsx b/frontend/src/routes/Settings/index.jsx
new file mode 100644
index 00000000..d7507a0a
--- /dev/null
+++ b/frontend/src/routes/Settings/index.jsx
@@ -0,0 +1 @@
+export { default } from "./Settings.jsx";
diff --git a/yarn.lock b/yarn.lock
index 4ca548d9..6cb6fc79 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -265,6 +265,15 @@ __metadata:
languageName: node
linkType: hard
+"@babel/runtime@npm:^7.19.4, @babel/runtime@npm:^7.22.5":
+ version: 7.23.2
+ resolution: "@babel/runtime@npm:7.23.2"
+ dependencies:
+ regenerator-runtime: "npm:^0.14.0"
+ checksum: abdcbdd590c7e31762e1bdab94dd466823c8bcedd3ff2fde85eeb94dac7cccaef151ac37c428bda7018ededd27c9a82b4dfeb621f978ad934232475a902f8e3a
+ languageName: node
+ linkType: hard
+
"@babel/template@npm:^7.22.15":
version: 7.22.15
resolution: "@babel/template@npm:7.22.15"
@@ -860,6 +869,22 @@ __metadata:
languageName: node
linkType: hard
+"@lit-labs/ssr-dom-shim@npm:^1.0.0, @lit-labs/ssr-dom-shim@npm:^1.1.0":
+ version: 1.1.2
+ resolution: "@lit-labs/ssr-dom-shim@npm:1.1.2"
+ checksum: a930f7de57b952dc21317a5754aa0411e000bb4991053cde771c111b7792c4a4cdc896922f0353c832215bed71400431c5ab5a6252c8f4f70bb9ce0b37fe4752
+ languageName: node
+ linkType: hard
+
+"@lit/reactive-element@npm:^1.3.0, @lit/reactive-element@npm:^1.6.0":
+ version: 1.6.3
+ resolution: "@lit/reactive-element@npm:1.6.3"
+ dependencies:
+ "@lit-labs/ssr-dom-shim": "npm:^1.0.0"
+ checksum: 664c899bb0b144590dc4faf83b358b1504810eac107778c3aeb384affc65a7ef4eda754944bcc34a57237db03dff145332406345ac24da19ca37cf4b3cb343d3
+ languageName: node
+ linkType: hard
+
"@material-ui/core@npm:^4.12.4":
version: 4.12.4
resolution: "@material-ui/core@npm:4.12.4"
@@ -980,6 +1005,16 @@ __metadata:
languageName: node
linkType: hard
+"@material/mwc-icon@npm:0.25.3":
+ version: 0.25.3
+ resolution: "@material/mwc-icon@npm:0.25.3"
+ dependencies:
+ lit: "npm:^2.0.0"
+ tslib: "npm:^2.0.1"
+ checksum: ee4eb4c746795666b576395046238f72714e7f3985e33a2edec8e11d3f9a2e11087edae70c6ba5b1804ff5348fe85a19a752281af97dff3c9ebad1b20f5969ea
+ languageName: node
+ linkType: hard
+
"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
@@ -1432,6 +1467,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/trusted-types@npm:^2.0.2":
+ version: 2.0.4
+ resolution: "@types/trusted-types@npm:2.0.4"
+ checksum: 5256c4576cd1c90d33ddd9cc9cbd4f202b39c98cbe8b7f74963298f9eb2159c285ea5c25a6181b4c594d8d75641765bff85d72c2d251ad076e6529ce0eeedd1c
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/eslint-plugin@npm:^6.7.4":
version: 6.7.4
resolution: "@typescript-eslint/eslint-plugin@npm:6.7.4"
@@ -2992,6 +3034,15 @@ __metadata:
languageName: node
linkType: hard
+"cross-fetch@npm:3.1.6":
+ version: 3.1.6
+ resolution: "cross-fetch@npm:3.1.6"
+ dependencies:
+ node-fetch: "npm:^2.6.11"
+ checksum: e08325b813da37f2d5312b3e630af992c35681c1737707b029e8ef1c48ea034bda8b960000fc8bee6e0485e133347198aa6ecccadb530b06c47472f6c76bc27b
+ languageName: node
+ linkType: hard
+
"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3":
version: 7.0.3
resolution: "cross-spawn@npm:7.0.3"
@@ -4344,11 +4395,16 @@ __metadata:
eslint-plugin-react-hooks: "npm:^4.6.0"
eslint-plugin-react-refresh: "npm:^0.4.3"
history: "npm:^5.3.0"
+ i18next: "npm:^23.5.1"
+ i18next-browser-languagedetector: "npm:^7.1.0"
+ i18next-http-backend: "npm:^2.2.2"
ipaddr.js: "npm:^2.0.1"
lodash: "npm:^4.17.21"
+ ninja-keys: "npm:^1.2.2"
react: "npm:^17.0.2"
react-data-table-component: "npm:^6.11.8"
react-dom: "npm:^17.0.2"
+ react-i18next: "npm:^13.3.0"
react-is: "npm:^17.0.2"
react-router-dom: "npm:^5.2.0"
react-use: "npm:^17.4.0"
@@ -4888,6 +4944,22 @@ __metadata:
languageName: node
linkType: hard
+"hotkeys-js@npm:3.8.7":
+ version: 3.8.7
+ resolution: "hotkeys-js@npm:3.8.7"
+ checksum: a70b797ae26ea89e9f0bef49711a48622422b641362ee0c2ac4a1f70794e85066623fefdf200866fce1f75fc520e530e35ebd0334f61cbf500da882a6b795faf
+ languageName: node
+ linkType: hard
+
+"html-parse-stringify@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "html-parse-stringify@npm:3.0.1"
+ dependencies:
+ void-elements: "npm:3.1.0"
+ checksum: 8743b76cc50e46d1956c1ad879d18eb9613b0d2d81e24686d633f9f69bb26b84676f64a926973de793cca479997017a63219278476d617b6c42d68246d7c07fe
+ languageName: node
+ linkType: hard
+
"http-cache-semantics@npm:^4.1.1":
version: 4.1.1
resolution: "http-cache-semantics@npm:4.1.1"
@@ -4968,6 +5040,33 @@ __metadata:
languageName: node
linkType: hard
+"i18next-browser-languagedetector@npm:^7.1.0":
+ version: 7.1.0
+ resolution: "i18next-browser-languagedetector@npm:7.1.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.19.4"
+ checksum: 3b06c8a5df09092cffc0b6637b542bb572e8a25dcba97d0d8a5e5dd7539b90bf00000f3a279654693f4b5908c5fc4d1d4f3766dfb461dacab46be3d071266384
+ languageName: node
+ linkType: hard
+
+"i18next-http-backend@npm:^2.2.2":
+ version: 2.2.2
+ resolution: "i18next-http-backend@npm:2.2.2"
+ dependencies:
+ cross-fetch: "npm:3.1.6"
+ checksum: dbf09f2f309cb6070e691d0d382ccff3e94d2cfa9f30315dc4c03faa5d7d1f3b408d48c46c766b7e07527ec10c0542fde19240845905314ce0134ac10d6a6adb
+ languageName: node
+ linkType: hard
+
+"i18next@npm:^23.5.1":
+ version: 23.5.1
+ resolution: "i18next@npm:23.5.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.22.5"
+ checksum: 38e62d582b0f67eb2eee4f079c9cd512246496f2fb970f50a0be26c7c5e6ac5e772de9763ac1943919ecd816b2c0375f4b2071c67b1485a6a980c4d37348408f
+ languageName: node
+ linkType: hard
+
"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24":
version: 0.4.24
resolution: "iconv-lite@npm:0.4.24"
@@ -5870,6 +5969,48 @@ __metadata:
languageName: node
linkType: hard
+"lit-element@npm:^3.2.0, lit-element@npm:^3.3.0":
+ version: 3.3.3
+ resolution: "lit-element@npm:3.3.3"
+ dependencies:
+ "@lit-labs/ssr-dom-shim": "npm:^1.1.0"
+ "@lit/reactive-element": "npm:^1.3.0"
+ lit-html: "npm:^2.8.0"
+ checksum: 7968e7f3ce3994911f27c4c54acc956488c91d8af81677cce3d6f0c2eaea45cceb79b064077159392238d6e43d46015a950269db9914fea8913566aacb17eaa1
+ languageName: node
+ linkType: hard
+
+"lit-html@npm:^2.2.0, lit-html@npm:^2.8.0":
+ version: 2.8.0
+ resolution: "lit-html@npm:2.8.0"
+ dependencies:
+ "@types/trusted-types": "npm:^2.0.2"
+ checksum: 3503e55e2927c2ff94773cf041fc4128f92291869c9192f36eacb7f95132d11f6b329e5b910ab60a4456349cd2e6d23b33d83291b24d557bcd6b904d6314ac1a
+ languageName: node
+ linkType: hard
+
+"lit@npm:2.2.6":
+ version: 2.2.6
+ resolution: "lit@npm:2.2.6"
+ dependencies:
+ "@lit/reactive-element": "npm:^1.3.0"
+ lit-element: "npm:^3.2.0"
+ lit-html: "npm:^2.2.0"
+ checksum: 160363c6d271559f629404301f4df324f97f0d7f48c69c784f277fdeabc5f975ab98cb792198136c87175f185b28699ff25c105dc91f08eb4e96e46143a6c162
+ languageName: node
+ linkType: hard
+
+"lit@npm:^2.0.0":
+ version: 2.8.0
+ resolution: "lit@npm:2.8.0"
+ dependencies:
+ "@lit/reactive-element": "npm:^1.6.0"
+ lit-element: "npm:^3.3.0"
+ lit-html: "npm:^2.8.0"
+ checksum: aa64c1136b855ba328d41157dba67657d480345aeec3c1dd829abeb67719d759c9ff2ade9903f9cfb4f9d012b16087034aaa5b33f1182e70c615765562e3251b
+ languageName: node
+ linkType: hard
+
"load-json-file@npm:^4.0.0":
version: 4.0.0
resolution: "load-json-file@npm:4.0.0"
@@ -6532,6 +6673,31 @@ __metadata:
languageName: node
linkType: hard
+"ninja-keys@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "ninja-keys@npm:1.2.2"
+ dependencies:
+ "@material/mwc-icon": "npm:0.25.3"
+ hotkeys-js: "npm:3.8.7"
+ lit: "npm:2.2.6"
+ checksum: 5f573fd547c54f926d13f30877f8e54245ec22097f0a539f9b89532aa4c21582572f7df4dc1db407f128fb44867fc9ef23e8c9065a36c5870652057b7149db73
+ languageName: node
+ linkType: hard
+
+"node-fetch@npm:^2.6.11":
+ version: 2.7.0
+ resolution: "node-fetch@npm:2.7.0"
+ dependencies:
+ whatwg-url: "npm:^5.0.0"
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+ checksum: b24f8a3dc937f388192e59bcf9d0857d7b6940a2496f328381641cb616efccc9866e89ec43f2ec956bbd6c3d3ee05524ce77fe7b29ccd34692b3a16f237d6676
+ languageName: node
+ linkType: hard
+
"node-gyp@npm:latest":
version: 9.4.0
resolution: "node-gyp@npm:9.4.0"
@@ -7288,6 +7454,24 @@ __metadata:
languageName: node
linkType: hard
+"react-i18next@npm:^13.3.0":
+ version: 13.3.0
+ resolution: "react-i18next@npm:13.3.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.22.5"
+ html-parse-stringify: "npm:^3.0.1"
+ peerDependencies:
+ i18next: ">= 23.2.3"
+ react: ">= 16.8.0"
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+ react-native:
+ optional: true
+ checksum: 2ef46245ba1ba9fca8c43dbe1bcab4ac63ca68e67de7159cb5f93cd7fd10407599bcdf1999f6567091987be7b9aaba77cdb515a70d5ee2b935b985f4c40d6d9d
+ languageName: node
+ linkType: hard
+
"react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0":
version: 16.13.1
resolution: "react-is@npm:16.13.1"
@@ -8654,6 +8838,13 @@ __metadata:
languageName: node
linkType: hard
+"tr46@npm:~0.0.3":
+ version: 0.0.3
+ resolution: "tr46@npm:0.0.3"
+ checksum: 8f1f5aa6cb232f9e1bdc86f485f916b7aa38caee8a778b378ffec0b70d9307873f253f5cbadbe2955ece2ac5c83d0dc14a77513166ccd0a0c7fe197e21396695
+ languageName: node
+ linkType: hard
+
"tree-kill@npm:^1.2.2":
version: 1.2.2
resolution: "tree-kill@npm:1.2.2"
@@ -8736,7 +8927,7 @@ __metadata:
languageName: node
linkType: hard
-"tslib@npm:^2.1.0":
+"tslib@npm:^2.0.1, tslib@npm:^2.1.0":
version: 2.6.2
resolution: "tslib@npm:2.6.2"
checksum: bd26c22d36736513980091a1e356378e8b662ded04204453d353a7f34a4c21ed0afc59b5f90719d4ba756e581a162ecbf93118dc9c6be5acf70aa309188166ca
@@ -9046,6 +9237,13 @@ __metadata:
languageName: node
linkType: hard
+"void-elements@npm:3.1.0":
+ version: 3.1.0
+ resolution: "void-elements@npm:3.1.0"
+ checksum: 0390f818107fa8fce55bb0a5c3f661056001c1d5a2a48c28d582d4d847347c2ab5b7f8272314cac58acf62345126b6b09bea623a185935f6b1c3bbce0dfd7f7f
+ languageName: node
+ linkType: hard
+
"wcwidth@npm:^1.0.1":
version: 1.0.1
resolution: "wcwidth@npm:1.0.1"
@@ -9055,6 +9253,23 @@ __metadata:
languageName: node
linkType: hard
+"webidl-conversions@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "webidl-conversions@npm:3.0.1"
+ checksum: b65b9f8d6854572a84a5c69615152b63371395f0c5dcd6729c45789052296df54314db2bc3e977df41705eacb8bc79c247cee139a63fa695192f95816ed528ad
+ languageName: node
+ linkType: hard
+
+"whatwg-url@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "whatwg-url@npm:5.0.0"
+ dependencies:
+ tr46: "npm:~0.0.3"
+ webidl-conversions: "npm:^3.0.0"
+ checksum: f95adbc1e80820828b45cc671d97da7cd5e4ef9deb426c31bcd5ab00dc7103042291613b3ef3caec0a2335ed09e0d5ed026c940755dbb6d404e2b27f940fdf07
+ languageName: node
+ linkType: hard
+
"which-boxed-primitive@npm:^1.0.2":
version: 1.0.2
resolution: "which-boxed-primitive@npm:1.0.2"