Skip to content

Commit

Permalink
Merge pull request #182 from aruznieto/i18n
Browse files Browse the repository at this point in the history
feat: i18n
  • Loading branch information
dec0dOS authored Oct 19, 2023
2 parents 213c949 + ee73374 commit 4a5f846
Show file tree
Hide file tree
Showing 30 changed files with 555 additions and 97 deletions.
2 changes: 1 addition & 1 deletion backend/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const loginLimiter = rateLimit({
max: Number(process.env.ZU_LOGIN_LIMIT_ATTEMPTS) || 50, // limit each IP to 50 requests per windowMs
message: {
status: 429,
error: "Too many login attempts, please try again in 15 minutes.",
error: "tooManyAttempts",
},
});

Expand Down
4 changes: 2 additions & 2 deletions backend/services/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ export async function authorize(username, password, callback) {
throw err;
}
const user = users.find({ username: username });
if (!user.value()) return callback(new Error("Invalid username or password")); // If return "user not found" someone can do a user listing
if (!user.value()) return callback(new Error("logInFailed")); // If return "user not found" someone can do a user listing
const verified = await verifyHash(password, user.value()["password_hash"]);
if (verified) {
return callback(null, user.value());
} else {
return callback(new Error("Invalid username or password"));
return callback(new Error("logInFailed"));
}
}

Expand Down
4 changes: 4 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@
"codemirror": "^5.62.3",
"date-fns": "^2.29.2",
"history": "^5.3.0",
"i18next": "^23.5.1",
"i18next-browser-languagedetector": "^7.1.0",
"i18next-http-backend": "^2.2.2",
"ipaddr.js": "^2.0.1",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-data-table-component": "^6.11.8",
"react-dom": "^17.0.2",
"react-i18next": "^13.3.0",
"react-is": "^17.0.2",
"react-router-dom": "^5.2.0",
"react-use": "^17.4.0",
Expand Down
67 changes: 67 additions & 0 deletions frontend/public/locales/en/common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"flowRules": "Flow Rules",
"createNetwork": "Create A Network",
"createOneNetwork": "Please create at least one network",
"controllerNetworks": "Controller networks",
"network_one": "Network",
"network_other": "Networks",
"controllerAddress": "Network controller address",
"loginToContinue": "Please, Log In to continue",
"zerouiDesc": "ZeroUI - ZeroTier Controller Web UI - is a web user interface for a self-hosted ZeroTier network controller.",
"logIn": "Log In",
"logInToken": "Token Log In",
"cancel": "Cancel",
"management": "Management",
"deleteNetwork": "Delete Network",
"deleteAlert": "This action cannot be undone.",
"deleteNetworkConfirm": "Are you sure you want to delete this network?",
"deleteMemberConfirm": "Are you sure you want to delete this member?",
"delete": "Delete",
"logOut": "Log out",
"advancedFeature": "ADVANCED FEATURE",
"noDevices": "No devices have joined this network. Use the app on your devices to join",
"member_one": "Member",
"member_other": "Members",
"addMemberManually": "Manually Add Member",
"name": "Name",
"description": "Description",
"allowBridging": "Allow Ethernet Bridging",
"noAutoIP": "Do Not Auto-Assign IPs",
"capabilities": "Capabilities",
"noCapDef": "No capabilities defined",
"tags": "Tags",
"noTagDef": "No tags defined",
"authorized": "Authorized",
"address": "Address",
"managedIPs": "Managed IPs",
"lastSeen": "Last seen",
"version": "Version",
"physIp": "Physical IP",
"latency": "Latency",
"settings": "Settings",
"generalSettings": "General settings",
"networkId": "Network ID",
"accessControl": "Access control",
"public": "Public",
"private": "Private",
"managedRoutes": "Managed routes",
"addRoute": "Add route",
"target": "Target",
"via": "Via",
"start": "Start",
"end": "End",
"ipv4AutoAssign": "IPv4 Auto-Assign",
"autoAssignPool": "IPv4 Auto-Assign",
"addIPv4Pool": "Add IPv4 Pool",
"multicastLimit": "Multicast Recipient Limit",
"enableBroadcast": "Enable Broadcast",
"logInFailed": "Invalid username or password",
"tooManyAttempts": "Too many login attempts, please try again in 15 minutes.",
"language": "Language",
"notAuthorized": "You are not authorized. Please Log In.",
"saveChanges": "Save changes",
"optional": "Optional",
"destination": "Destination",
"username": "Username",
"password": "Password"
}
67 changes: 67 additions & 0 deletions frontend/public/locales/es-ES/common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"flowRules": "Reglas de flujo",
"createNetwork": "Crear una red",
"createOneNetwork": "Por favor, crea al menos una red",
"controllerNetworks": "Controlador de redes",
"network_one": "Red",
"network_other": "Redes",
"controllerAddress": "Dirección del controlador",
"loginToContinue": "Por favor, inicia sesión para continuar",
"zerouiDesc": "ZeroUI - ZeroTier Controller Web UI - es una interfaz de usuario web para un controlador de red ZeroTier self-hosted.",
"logIn": "Iniciar sesión",
"logInToken": "Iniciar sesión con token",
"cancel": "Cancelar",
"management": "Gestión",
"deleteNetwork": "Borrar red",
"deleteAlert": "Esta acción no puede ser revertida.",
"deleteNetworkConfirm": "¿Seguro que deseas borrar esta red?",
"deleteMemberConfirm": "¿Seguro que deseas borrar este usuario?",
"delete": "Borrar",
"logOut": "Cerrar sesión",
"advancedFeature": "CARACTERÍSTICA AVANZADA",
"noDevices": "Ningún dispositivo se ha unido a esta red. Utilice la aplicación en sus dispositivos para unirse",
"member_one": "Miembro",
"member_other": "Miembros",
"addMemberManually": "Añadir miembro manualmente",
"name": "Nombre",
"description": "Descripción",
"allowBridging": "Permitir puente Ethernet",
"noAutoIP": "No autoasignar IPs",
"capabilities": "Permisos",
"noCapDef": "No hay permisos definidos",
"tags": "Etiquetas",
"noTagDef": "No hay etiquetas definidas",
"authorized": "Autorizado",
"address": "Dirección",
"managedIPs": "IPs asignadas",
"lastSeen": "Visto por última vez",
"version": "Versión",
"physIp": "IP pública",
"latency": "Latencia",
"settings": "Ajustes",
"generalSettings": "Ajustes generales",
"networkId": "ID de red",
"accessControl": "Control de acceso",
"public": "Público",
"private": "Privado",
"managedRoutes": "Rutas gestionadas",
"addRoute": "Añadir ruta",
"target": "Objetivo",
"via": "Vía",
"start": "Inicio",
"end": "Final",
"autoAssignPool": "Rango de IPv4 autoasignables",
"ipv4AutoAssign": "Rangos de IPv4 automáticos",
"addIPv4Pool": "Añadir rango IPv4",
"multicastLimit": "Límite de destinatarios multicast",
"enableBroadcast": "Habilitar broadcast",
"logInFailed": "Nombre de usuario o contraseña incorrecto",
"tooManyAttempts": "Demasiados intentos de inicio de sesión. Vuelvee a intentarlo en 15 minutos",
"language": "Idioma",
"notAuthorized": "No estás autorizado. Por favor, inicia sesión.",
"saveChanges": "Guardar cambios",
"optional": "Opcional",
"destination": "Destino",
"username": "Nombre de usuario",
"password": "Contraseña"
}
2 changes: 2 additions & 0 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Bar from "./components/Bar";
import Home from "./routes/Home";
import NotFound from "./routes/NotFound";
import Network from "./routes/Network/Network";
import Settings from "./routes/Settings";

function App() {
return (
Expand All @@ -17,6 +18,7 @@ function App() {
<Switch>
<Route exact path="/" component={Home} />
<Route path="/network/:nwid" component={Network} />
<Route path="/settings" component={Settings} />
<Route path="/404" component={NotFound} />
<Redirect to="/404" />
</Switch>
Expand Down
15 changes: 9 additions & 6 deletions frontend/src/components/Bar/Bar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import MenuIcon from "@material-ui/icons/Menu";

import LogIn from "components/LogIn";

import { useTranslation } from "react-i18next";

function Bar() {
const [loggedIn, setLoggedIn] = useLocalStorage("loggedIn", false);
const [disabledAuth] = useLocalStorage("disableAuth", false);
Expand All @@ -41,16 +43,18 @@ function Bar() {
history.go(0);
};

const { t, i18n } = useTranslation();

const menuItems = [
// TODO: add settings page
// {
// name: "Settings",
// to: "/settings",
// },
{
name: t("settings"),
to: "/settings",
},
...(!disabledAuth
? [
{
name: "Log out",
name: t("logOut"),
divide: true,
onClick: onLogOutClick,
},
Expand Down Expand Up @@ -115,7 +119,6 @@ function Bar() {
key={index}
onClick={() => {
closeMenu();

menuItem.onClick();
}}
>
Expand Down
14 changes: 9 additions & 5 deletions frontend/src/components/HomeLoggedIn/HomeLoggedIn.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import NetworkButton from "./components/NetworkButton";
import API from "utils/API";
import { generateNetworkConfig } from "utils/NetworkConfig";

import { useTranslation } from "react-i18next";

function HomeLoggedIn() {
const [networks, setNetworks] = useState([]);

Expand All @@ -30,6 +32,8 @@ function HomeLoggedIn() {
fetchData();
}, []);

const { t, i18n } = useTranslation();

return (
<div className={classes.root}>
<Button
Expand All @@ -38,19 +42,19 @@ function HomeLoggedIn() {
className={classes.createBtn}
onClick={createNetwork}
>
Create A Network
{t("createNetwork")}
</Button>
<Divider />
<Grid container spacing={3} className={classes.container}>
<Grid item xs={6}>
<Typography variant="h5">Controller networks</Typography>
{networks[0] && "Network controller address"}
<Typography variant="h5">{t("controllerNetworks")}</Typography>
{networks[0] && t("controllerAddress")}
<Box fontWeight="fontWeightBold">
{networks[0] && networks[0]["id"].slice(0, 10)}
</Box>
</Grid>
<Grid item xs="auto">
<Typography>Networks</Typography>
<Typography>{t("network", { count: networks.length })}</Typography>
<Grid item>
{networks[0] ? (
networks.map((network) => (
Expand All @@ -59,7 +63,7 @@ function HomeLoggedIn() {
</Grid>
))
) : (
<div>Please create at least one network</div>
<div>{t("createOneNetwork")}</div>
)}
</Grid>
</Grid>
Expand Down
11 changes: 6 additions & 5 deletions frontend/src/components/HomeLoggedOut/HomeLoggedOut.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -29,6 +31,8 @@ function HomeLoggedOut() {
fetchData();
}, [history, setDisableAuth, setLoggedIn, setToken]);

const { t, i18n } = useTranslation();

return (
<Grid
container
Expand All @@ -42,14 +46,11 @@ function HomeLoggedOut() {
>
<Grid item xs={10}>
<Typography variant="h5">
<span>
ZeroUI - ZeroTier Controller Web UI - is a web user interface for a
self-hosted ZeroTier network controller.
</span>
<span>{t("zerouiDesc")}</span>
</Typography>

<Typography>
<span>Please Log In to continue</span>
<span>{t("loginToContinue")}</span>
</Typography>
</Grid>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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("");
Expand Down Expand Up @@ -41,6 +43,8 @@ function LogInToken() {
}
};

const { t, i18n } = useTranslation();

const LogIn = () => {
if (token.length !== 32) {
setErrorText("Token length error");
Expand All @@ -55,12 +59,12 @@ function LogInToken() {
return (
<div>
<Button onClick={handleClickOpen} color="inherit" variant="outlined">
Token Log In
{t("logInToken")}
</Button>
<Dialog open={open} onClose={handleClose} onKeyPress={handleKeyPress}>
<DialogTitle>Log In</DialogTitle>
<DialogTitle>{t("logIn")}</DialogTitle>
<DialogContent>
<DialogContentText>ADVANCED FEATURE.</DialogContentText>
<DialogContentText>{t("advancedFeature")}</DialogContentText>
<TextField
value={token}
onChange={(e) => {
Expand All @@ -76,10 +80,10 @@ function LogInToken() {
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Cancel
{t("cancel")}
</Button>
<Button onClick={LogIn} color="primary">
Log In
{t("logIn")}
</Button>
</DialogActions>
</Dialog>
Expand Down
Loading

0 comments on commit 4a5f846

Please sign in to comment.