refactor: rename site to frontend
24
frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
3
frontend/.prettierignore
Normal file
@@ -0,0 +1,3 @@
|
||||
# Ignore artifacts:
|
||||
dist
|
||||
node_modules
|
||||
1
frontend/.prettierrc
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
23
frontend/Dockerfile.dev
Normal file
@@ -0,0 +1,23 @@
|
||||
FROM oven/bun:1.1.45-alpine
|
||||
|
||||
WORKDIR /frontend
|
||||
|
||||
COPY ./frontend/package.json ./
|
||||
COPY ./frontend/bun.lockb ./
|
||||
|
||||
RUN bun install
|
||||
|
||||
COPY ./frontend/public ./public
|
||||
COPY ./frontend/src ./src
|
||||
|
||||
COPY ./frontend/eslint.config.js ./
|
||||
COPY ./frontend/index.html ./
|
||||
COPY ./frontend/tsconfig.json ./
|
||||
COPY ./frontend/tsconfig.app.json ./
|
||||
COPY ./frontend/tsconfig.node.json ./
|
||||
COPY ./frontend/vite.config.ts ./
|
||||
COPY ./frontend/postcss.config.cjs ./
|
||||
|
||||
EXPOSE 5173
|
||||
|
||||
ENTRYPOINT ["bun", "run", "dev"]
|
||||
BIN
frontend/bun.lockb
Executable file
28
frontend/eslint.config.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import reactHooks from "eslint-plugin-react-hooks";
|
||||
import reactRefresh from "eslint-plugin-react-refresh";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ["dist"] },
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ["**/*.{ts,tsx}"],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
"react-hooks": reactHooks,
|
||||
"react-refresh": reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
"react-refresh/only-export-components": [
|
||||
"warn",
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
16
frontend/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/frontend.webmanifest" />
|
||||
<title>Tinyauth</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
2249
frontend/package-lock.json
generated
Normal file
45
frontend/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mantine/core": "^7.16.0",
|
||||
"@mantine/form": "^7.16.0",
|
||||
"@mantine/hooks": "^7.16.0",
|
||||
"@mantine/notifications": "^7.16.0",
|
||||
"@tanstack/react-query": "4",
|
||||
"axios": "^1.7.9",
|
||||
"i18next": "^24.2.3",
|
||||
"i18next-browser-languagedetector": "^8.0.4",
|
||||
"i18next-resources-to-backend": "^1.2.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^15.4.1",
|
||||
"react-router": "^7.1.3",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.17.0",
|
||||
"@types/react": "^18.3.18",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"eslint": "^9.17.0",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.16",
|
||||
"globals": "^15.14.0",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss-preset-mantine": "^1.17.0",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"prettier": "3.4.2",
|
||||
"typescript": "~5.6.2",
|
||||
"typescript-eslint": "^8.18.2",
|
||||
"vite": "^6.0.5"
|
||||
}
|
||||
}
|
||||
14
frontend/postcss.config.cjs
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
"postcss-preset-mantine": {},
|
||||
"postcss-simple-vars": {
|
||||
variables: {
|
||||
"mantine-breakpoint-xs": "36em",
|
||||
"mantine-breakpoint-sm": "48em",
|
||||
"mantine-breakpoint-md": "62em",
|
||||
"mantine-breakpoint-lg": "75em",
|
||||
"mantine-breakpoint-xl": "88em",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
BIN
frontend/public/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
frontend/public/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
frontend/public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
frontend/public/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 602 B |
BIN
frontend/public/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
frontend/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
frontend/public/logo.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
1
frontend/public/site.webmanifest
Normal file
@@ -0,0 +1 @@
|
||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
||||
17
frontend/src/App.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Navigate } from "react-router";
|
||||
import { useUserContext } from "./context/user-context";
|
||||
import { LogoutPage } from "./pages/logout-page";
|
||||
|
||||
export const App = () => {
|
||||
const queryString = window.location.search;
|
||||
const params = new URLSearchParams(queryString);
|
||||
const redirectUri = params.get("redirect_uri");
|
||||
|
||||
const { isLoggedIn } = useUserContext();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
return <Navigate to={`/login?redirect_uri=${redirectUri}`} />;
|
||||
}
|
||||
|
||||
return <LogoutPage />;
|
||||
};
|
||||
48
frontend/src/components/auth/login-forn.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { TextInput, PasswordInput, Button } from "@mantine/core";
|
||||
import { useForm, zodResolver } from "@mantine/form";
|
||||
import { LoginFormValues, loginSchema } from "../../schemas/login-schema";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface LoginFormProps {
|
||||
isLoading: boolean;
|
||||
onSubmit: (values: LoginFormValues) => void;
|
||||
}
|
||||
|
||||
export const LoginForm = (props: LoginFormProps) => {
|
||||
const { isLoading, onSubmit } = props;
|
||||
const { t } = useTranslation();
|
||||
|
||||
const form = useForm({
|
||||
mode: "uncontrolled",
|
||||
initialValues: {
|
||||
username: "",
|
||||
password: "",
|
||||
},
|
||||
validate: zodResolver(loginSchema),
|
||||
});
|
||||
|
||||
return (
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<TextInput
|
||||
label={t("loginUsername")}
|
||||
placeholder="user@example.com"
|
||||
required
|
||||
disabled={isLoading}
|
||||
key={form.key("username")}
|
||||
{...form.getInputProps("username")}
|
||||
/>
|
||||
<PasswordInput
|
||||
label={t("loginPassword")}
|
||||
placeholder="password"
|
||||
required
|
||||
mt="md"
|
||||
disabled={isLoading}
|
||||
key={form.key("password")}
|
||||
{...form.getInputProps("password")}
|
||||
/>
|
||||
<Button fullWidth mt="xl" type="submit" loading={isLoading}>
|
||||
{t("loginSubmit")}
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
72
frontend/src/components/auth/oauth-buttons.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Grid, Button } from "@mantine/core";
|
||||
import { GithubIcon } from "../../icons/github";
|
||||
import { GoogleIcon } from "../../icons/google";
|
||||
import { OAuthIcon } from "../../icons/oauth";
|
||||
import { TailscaleIcon } from "../../icons/tailscale";
|
||||
|
||||
interface OAuthButtonsProps {
|
||||
oauthProviders: string[];
|
||||
isLoading: boolean;
|
||||
mutate: (provider: string) => void;
|
||||
genericName: string;
|
||||
}
|
||||
|
||||
export const OAuthButtons = (props: OAuthButtonsProps) => {
|
||||
const { oauthProviders, isLoading, genericName, mutate } = props;
|
||||
return (
|
||||
<Grid mb="md" mt="md" align="center" justify="center">
|
||||
{oauthProviders.includes("google") && (
|
||||
<Grid.Col span="content">
|
||||
<Button
|
||||
radius="xl"
|
||||
leftSection={<GoogleIcon style={{ width: 14, height: 14 }} />}
|
||||
variant="default"
|
||||
onClick={() => mutate("google")}
|
||||
loading={isLoading}
|
||||
>
|
||||
Google
|
||||
</Button>
|
||||
</Grid.Col>
|
||||
)}
|
||||
{oauthProviders.includes("github") && (
|
||||
<Grid.Col span="content">
|
||||
<Button
|
||||
radius="xl"
|
||||
leftSection={<GithubIcon style={{ width: 14, height: 14 }} />}
|
||||
variant="default"
|
||||
onClick={() => mutate("github")}
|
||||
loading={isLoading}
|
||||
>
|
||||
Github
|
||||
</Button>
|
||||
</Grid.Col>
|
||||
)}
|
||||
{oauthProviders.includes("tailscale") && (
|
||||
<Grid.Col span="content">
|
||||
<Button
|
||||
radius="xl"
|
||||
leftSection={<TailscaleIcon style={{ width: 14, height: 14 }} />}
|
||||
variant="default"
|
||||
onClick={() => mutate("tailscale")}
|
||||
loading={isLoading}
|
||||
>
|
||||
Tailscale
|
||||
</Button>
|
||||
</Grid.Col>
|
||||
)}
|
||||
{oauthProviders.includes("generic") && (
|
||||
<Grid.Col span="content">
|
||||
<Button
|
||||
radius="xl"
|
||||
leftSection={<OAuthIcon style={{ width: 14, height: 14 }} />}
|
||||
variant="default"
|
||||
onClick={() => mutate("generic")}
|
||||
loading={isLoading}
|
||||
>
|
||||
{genericName}
|
||||
</Button>
|
||||
</Grid.Col>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
40
frontend/src/components/auth/totp-form.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Button, PinInput } from "@mantine/core";
|
||||
import { useForm, zodResolver } from "@mantine/form";
|
||||
import { z } from "zod";
|
||||
|
||||
const schema = z.object({
|
||||
code: z.string(),
|
||||
});
|
||||
|
||||
type FormValues = z.infer<typeof schema>;
|
||||
|
||||
interface TotpFormProps {
|
||||
onSubmit: (values: FormValues) => void;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export const TotpForm = (props: TotpFormProps) => {
|
||||
const { onSubmit, isLoading } = props;
|
||||
|
||||
const form = useForm({
|
||||
mode: "uncontrolled",
|
||||
initialValues: {
|
||||
code: "",
|
||||
},
|
||||
validate: zodResolver(schema),
|
||||
});
|
||||
|
||||
return (
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<PinInput
|
||||
length={6}
|
||||
type={"number"}
|
||||
placeholder=""
|
||||
{...form.getInputProps("code")}
|
||||
/>
|
||||
<Button type="submit" mt="xl" loading={isLoading} fullWidth>
|
||||
Verify
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import { ComboboxItem, Select } from "@mantine/core";
|
||||
import { useState } from "react";
|
||||
import i18n from "../../lib/i18n/i18n";
|
||||
import {
|
||||
SupportedLanguage,
|
||||
getLanguageName,
|
||||
languages,
|
||||
} from "../../lib/i18n/locales";
|
||||
|
||||
export const LanguageSelector = () => {
|
||||
const [language, setLanguage] = useState<ComboboxItem>({
|
||||
value: i18n.language,
|
||||
label: getLanguageName(i18n.language as SupportedLanguage),
|
||||
});
|
||||
|
||||
const languageOptions = Object.entries(languages).map(([code, name]) => ({
|
||||
value: code,
|
||||
label: name,
|
||||
}));
|
||||
|
||||
const handleLanguageChange = (option: string) => {
|
||||
i18n.changeLanguage(option as SupportedLanguage);
|
||||
setLanguage({
|
||||
value: option,
|
||||
label: getLanguageName(option as SupportedLanguage),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Select
|
||||
data={languageOptions}
|
||||
value={language ? language.value : null}
|
||||
onChange={(_value, option) => handleLanguageChange(option.value)}
|
||||
allowDeselect={false}
|
||||
pos="absolute"
|
||||
right={10}
|
||||
top={10}
|
||||
/>
|
||||
);
|
||||
};
|
||||
16
frontend/src/components/layouts/layout.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Center, Flex } from "@mantine/core";
|
||||
import { ReactNode } from "react";
|
||||
import { LanguageSelector } from "../language-selector/language-selector";
|
||||
|
||||
export const Layout = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<>
|
||||
<LanguageSelector />
|
||||
<Center style={{ minHeight: "100vh" }}>
|
||||
<Flex direction="column" flex="1" maw={340}>
|
||||
{children}
|
||||
</Flex>
|
||||
</Center>
|
||||
</>
|
||||
);
|
||||
};
|
||||
42
frontend/src/context/app-context.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import React, { createContext, useContext } from "react";
|
||||
import axios from "axios";
|
||||
import { AppContextSchemaType } from "../schemas/app-context-schema";
|
||||
|
||||
const AppContext = createContext<AppContextSchemaType | null>(null);
|
||||
|
||||
export const AppContextProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const {
|
||||
data: userContext,
|
||||
isLoading,
|
||||
error,
|
||||
} = useQuery({
|
||||
queryKey: ["appContext"],
|
||||
queryFn: async () => {
|
||||
const res = await axios.get("/api/app");
|
||||
return res.data;
|
||||
},
|
||||
});
|
||||
|
||||
if (error && !isLoading) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return (
|
||||
<AppContext.Provider value={userContext}>{children}</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAppContext = () => {
|
||||
const context = useContext(AppContext);
|
||||
|
||||
if (context === null) {
|
||||
throw new Error("useAppContext must be used within an AppContextProvider");
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
42
frontend/src/context/user-context.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import React, { createContext, useContext } from "react";
|
||||
import axios from "axios";
|
||||
import { UserContextSchemaType } from "../schemas/user-context-schema";
|
||||
|
||||
const UserContext = createContext<UserContextSchemaType | null>(null);
|
||||
|
||||
export const UserContextProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const {
|
||||
data: userContext,
|
||||
isLoading,
|
||||
error,
|
||||
} = useQuery({
|
||||
queryKey: ["userContext"],
|
||||
queryFn: async () => {
|
||||
const res = await axios.get("/api/user");
|
||||
return res.data;
|
||||
},
|
||||
});
|
||||
|
||||
if (error && !isLoading) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return (
|
||||
<UserContext.Provider value={userContext}>{children}</UserContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useUserContext = () => {
|
||||
const context = useContext(UserContext);
|
||||
|
||||
if (context === null) {
|
||||
throw new Error("useUserContext must be used within a UserContextProvider");
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
18
frontend/src/icons/github.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { SVGProps } from "react";
|
||||
|
||||
export function GithubIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5c.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34c-.46-1.16-1.11-1.47-1.11-1.47c-.91-.62.07-.6.07-.6c1 .07 1.53 1.03 1.53 1.03c.87 1.52 2.34 1.07 2.91.83c.09-.65.35-1.09.63-1.34c-2.22-.25-4.55-1.11-4.55-4.92c0-1.11.38-2 1.03-2.71c-.1-.25-.45-1.29.1-2.64c0 0 .84-.27 2.75 1.02c.79-.22 1.65-.33 2.5-.33s1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02c.55 1.35.2 2.39.1 2.64c.65.71 1.03 1.6 1.03 2.71c0 3.82-2.34 4.66-4.57 4.91c.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
30
frontend/src/icons/google.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { SVGProps } from "react";
|
||||
|
||||
export function GoogleIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={48}
|
||||
height={48}
|
||||
viewBox="0 0 48 48"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="#ffc107"
|
||||
d="M43.611 20.083H42V20H24v8h11.303c-1.649 4.657-6.08 8-11.303 8c-6.627 0-12-5.373-12-12s5.373-12 12-12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4C12.955 4 4 12.955 4 24s8.955 20 20 20s20-8.955 20-20c0-1.341-.138-2.65-.389-3.917"
|
||||
></path>
|
||||
<path
|
||||
fill="#ff3d00"
|
||||
d="m6.306 14.691l6.571 4.819C14.655 15.108 18.961 12 24 12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4C16.318 4 9.656 8.337 6.306 14.691"
|
||||
></path>
|
||||
<path
|
||||
fill="#4caf50"
|
||||
d="M24 44c5.166 0 9.86-1.977 13.409-5.192l-6.19-5.238A11.9 11.9 0 0 1 24 36c-5.202 0-9.619-3.317-11.283-7.946l-6.522 5.025C9.505 39.556 16.227 44 24 44"
|
||||
></path>
|
||||
<path
|
||||
fill="#1976d2"
|
||||
d="M43.611 20.083H42V20H24v8h11.303a12.04 12.04 0 0 1-4.087 5.571l.003-.002l6.19 5.238C36.971 39.205 44 34 44 24c0-1.341-.138-2.65-.389-3.917"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
24
frontend/src/icons/oauth.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { SVGProps } from "react";
|
||||
|
||||
export function OAuthIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path d="M2 12a10 10 0 1 0 20 0a10 10 0 1 0-20 0"></path>
|
||||
<path d="M12.556 6c.65 0 1.235.373 1.508.947l2.839 7.848a1.646 1.646 0 0 1-1.01 2.108a1.673 1.673 0 0 1-2.068-.851L13.365 15h-2.73l-.398.905A1.67 1.67 0 0 1 8.26 16.95l-.153-.047a1.647 1.647 0 0 1-1.056-1.956l2.824-7.852a1.66 1.66 0 0 1 1.409-1.087z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
55
frontend/src/icons/tailscale.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import type { SVGProps } from "react";
|
||||
|
||||
export function TailscaleIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
width={24}
|
||||
height={24}
|
||||
{...props}
|
||||
>
|
||||
<style>{".st0{opacity:0.2;fill:#CCCAC9;}.st1{fill:#FFFFFF;}"}</style>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
className="st0"
|
||||
d="M65.6,127.7c35.3,0,63.9-28.6,63.9-63.9S100.9,0,65.6,0S1.8,28.6,1.8,63.9S30.4,127.7,65.6,127.7z"
|
||||
/>
|
||||
<path
|
||||
className="st1"
|
||||
d="M65.6,318.1c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9S1.8,219,1.8,254.2S30.4,318.1,65.6,318.1z"
|
||||
/>
|
||||
<path
|
||||
className="st0"
|
||||
d="M65.6,512c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9S1.8,412.9,1.8,448.1S30.4,512,65.6,512z"
|
||||
/>
|
||||
<path
|
||||
className="st1"
|
||||
d="M257.2,318.1c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9s-63.9,28.6-63.9,63.9S221.9,318.1,257.2,318.1z"
|
||||
/>
|
||||
<path
|
||||
className="st1"
|
||||
d="M257.2,512c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9s-63.9,28.6-63.9,63.9S221.9,512,257.2,512z"
|
||||
/>
|
||||
<path
|
||||
className="st0"
|
||||
d="M257.2,127.7c35.3,0,63.9-28.6,63.9-63.9S292.5,0,257.2,0s-63.9,28.6-63.9,63.9S221.9,127.7,257.2,127.7z"
|
||||
/>
|
||||
<path
|
||||
className="st0"
|
||||
d="M446.4,127.7c35.3,0,63.9-28.6,63.9-63.9S481.6,0,446.4,0c-35.3,0-63.9,28.6-63.9,63.9S411.1,127.7,446.4,127.7z"
|
||||
/>
|
||||
<path
|
||||
className="st1"
|
||||
d="M446.4,318.1c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9s-63.9,28.6-63.9,63.9S411.1,318.1,446.4,318.1z"
|
||||
/>
|
||||
<path
|
||||
className="st0"
|
||||
d="M446.4,512c35.3,0,63.9-28.6,63.9-63.9s-28.6-63.9-63.9-63.9s-63.9,28.6-63.9,63.9S411.1,512,446.4,512z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
19
frontend/src/lib/i18n/i18n.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import resourcesToBackend from 'i18next-resources-to-backend';
|
||||
|
||||
i18n
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.use(resourcesToBackend((language: string) => import(`./locales/${language}.json`)))
|
||||
.init({
|
||||
fallbackLng: 'en',
|
||||
debug: import.meta.env.MODE === 'development',
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
}
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
36
frontend/src/lib/i18n/locales.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
export const languages = {
|
||||
"af-ZA": "Afrikaans",
|
||||
"ar-SA": "العربية",
|
||||
"ca-ES": "Català",
|
||||
"cs-CZ": "Čeština",
|
||||
"da-DK": "Dansk",
|
||||
"de-DE": "Deutsch",
|
||||
"el-GR": "Ελληνικά",
|
||||
"en-US": "English",
|
||||
"es-ES": "Español",
|
||||
"fi-FI": "Suomi",
|
||||
"fr-FR": "Français",
|
||||
"he-IL": "עברית",
|
||||
"hu-HU": "Magyar",
|
||||
"it-IT": "Italiano",
|
||||
"ja-JP": "日本語",
|
||||
"ko-KR": "한국어",
|
||||
"nl-NL": "Nederlands",
|
||||
"no-NO": "Norsk",
|
||||
"pl-PL": "Polski",
|
||||
"pt-BR": "Português",
|
||||
"pt-PT": "Português",
|
||||
"ro-RO": "Română",
|
||||
"ru-RU": "Русский",
|
||||
"sr-SP": "Српски",
|
||||
"sv-SE": "Svenska",
|
||||
"tr-TR": "Türkçe",
|
||||
"uk-UA": "Українська",
|
||||
"vi-VN": "Tiếng Việt",
|
||||
"zh-CN": "中文",
|
||||
"zh-TW": "中文"
|
||||
}
|
||||
|
||||
export type SupportedLanguage = keyof typeof languages;
|
||||
|
||||
export const getLanguageName = (language: SupportedLanguage): string => languages[language];
|
||||
45
frontend/src/lib/i18n/locales/af-ZA.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/ar-SA.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/ca-ES.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/cs-CZ.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/da-DK.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/de-DE.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/el-GR.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Καλώς ήρθατε, συνδεθείτε με",
|
||||
"loginDivider": "Ή συνεχίστε με κωδικό πρόσβασης",
|
||||
"loginUsername": "Όνομα Χρήστη",
|
||||
"loginPassword": "Κωδικός",
|
||||
"loginSubmit": "Είσοδος",
|
||||
"loginFailTitle": "Αποτυχία σύνδεσης",
|
||||
"loginFailSubtitle": "Παρακαλώ ελέγξτε το όνομα χρήστη και τον κωδικό πρόσβασης",
|
||||
"loginSuccessTitle": "Συνδεδεμένος",
|
||||
"loginSuccessSubtitle": "Καλώς ήρθατε!",
|
||||
"loginOauthFailTitle": "Εσωτερικό σφάλμα",
|
||||
"loginOauthFailSubtitle": "Αποτυχία λήψης OAuth URL",
|
||||
"loginOauthSuccessTitle": "Ανακατεύθυνση",
|
||||
"loginOauthSuccessSubtitle": "Ανακατεύθυνση στον πάροχο OAuth σας",
|
||||
"continueRedirectingTitle": "Ανακατεύθυνση...",
|
||||
"continueRedirectingSubtitle": "Θα πρέπει να μεταφερθείτε σύντομα στην εφαρμογή σας",
|
||||
"continueInvalidRedirectTitle": "Μη έγκυρη ανακατεύθυνση",
|
||||
"continueInvalidRedirectSubtitle": "Το URL ανακατεύθυνσης δεν είναι έγκυρο",
|
||||
"continueInsecureRedirectTitle": "Μη ασφαλής ανακατεύθυνση",
|
||||
"continueInsecureRedirectSubtitle": "Προσπαθείτε να ανακατευθύνετε από <Code>https</Code> σε <Code>http</Code>, είστε σίγουροι ότι θέλετε να συνεχίσετε;",
|
||||
"continueTitle": "Συνέχεια",
|
||||
"continueSubtitle": "Κάντε κλικ στο κουμπί για να συνεχίσετε στην εφαρμογή σας.",
|
||||
"internalErrorTitle": "Εσωτερικό Σφάλμα Διακομιστή",
|
||||
"internalErrorSubtitle": "Παρουσιάστηκε σφάλμα στο διακομιστή και δεν μπορεί να εξυπηρετήσει το αίτημά σας.",
|
||||
"internalErrorButton": "Προσπαθήστε ξανά",
|
||||
"logoutFailTitle": "Αποτυχία αποσύνδεσης",
|
||||
"logoutFailSubtitle": "Παρακαλώ δοκιμάστε ξανά",
|
||||
"logoutSuccessTitle": "Αποσυνδεδεμένος",
|
||||
"logoutSuccessSubtitle": "Έχετε αποσυνδεθεί",
|
||||
"logoutTitle": "Αποσύνδεση",
|
||||
"logoutUsernameSubtitle": "Αυτή τη στιγμή είστε συνδεδεμένοι ως <Code>{{username}}</Code>, κάντε κλικ στο παρακάτω κουμπί για να αποσυνδεθείτε.",
|
||||
"logoutOauthSubtitle": "Αυτή τη στιγμή είστε συνδεδεμένοι ως <Code>{{username}}</Code> χρησιμοποιώντας την υπηρεσία παροχής {{provider}} OAuth, κάντε κλικ στο παρακάτω κουμπί για να αποσυνδεθείτε.",
|
||||
"notFoundTitle": "Η σελίδα δε βρέθηκε",
|
||||
"notFoundSubtitle": "Η σελίδα που ψάχνετε δεν υπάρχει.",
|
||||
"notFoundButton": "Μετάβαση στην αρχική",
|
||||
"totpFailTitle": "Αποτυχία επαλήθευσης κωδικού",
|
||||
"totpFailSubtitle": "Παρακαλώ ελέγξτε τον κώδικά σας και προσπαθήστε ξανά",
|
||||
"totpSuccessTitle": "Επαληθεύθηκε",
|
||||
"totpSuccessSubtitle": "Ανακατεύθυνση στην εφαρμογή σας",
|
||||
"totpTitle": "Εισάγετε τον κωδικό TOTP",
|
||||
"unauthorizedTitle": "Μη εξουσιοδοτημένο",
|
||||
"unauthorizedResourceSubtitle": "Ο χρήστης με όνομα χρήστη {{username}} δεν είναι εξουσιοδοτημένος να έχει πρόσβαση στον πόρο <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "Ο χρήστης με όνομα χρήστη {{username}} δεν είναι εξουσιοδοτημένος να συνδεθεί.",
|
||||
"unauthorizedButton": "Προσπαθήστε ξανά"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/en-US.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/en.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/es-ES.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/fi-FI.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/fr-FR.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Bienvenue, connectez-vous avec",
|
||||
"loginDivider": "Ou continuez avec le mot de passe",
|
||||
"loginUsername": "Nom d'utilisateur",
|
||||
"loginPassword": "Mot de passe",
|
||||
"loginSubmit": "Se connecter",
|
||||
"loginFailTitle": "Échec de la connexion",
|
||||
"loginFailSubtitle": "Veuillez vérifier votre nom d'utilisateur et votre mot de passe",
|
||||
"loginSuccessTitle": "Connecté",
|
||||
"loginSuccessSubtitle": "Bienvenue!",
|
||||
"loginOauthFailTitle": "Erreur interne",
|
||||
"loginOauthFailSubtitle": "Impossible d'obtenir l'URL OAuth",
|
||||
"loginOauthSuccessTitle": "Redirection",
|
||||
"loginOauthSuccessSubtitle": "Redirection vers votre fournisseur OAuth",
|
||||
"continueRedirectingTitle": "Redirection...",
|
||||
"continueRedirectingSubtitle": "Vous devriez être redirigé vers l'application bientôt",
|
||||
"continueInvalidRedirectTitle": "Redirection invalide",
|
||||
"continueInvalidRedirectSubtitle": "L'URL de redirection est invalide",
|
||||
"continueInsecureRedirectTitle": "Redirection non sécurisée",
|
||||
"continueInsecureRedirectSubtitle": "Vous essayez de rediriger de <Code>https</Code> vers <Code>http</Code>, êtes-vous sûr de vouloir continuer ?",
|
||||
"continueTitle": "Continuer",
|
||||
"continueSubtitle": "Cliquez sur le bouton pour continuer vers votre application.",
|
||||
"internalErrorTitle": "Erreur interne du serveur",
|
||||
"internalErrorSubtitle": "Une erreur s'est produite sur le serveur et il ne peut actuellement pas répondre à votre demande.",
|
||||
"internalErrorButton": "Réessayer",
|
||||
"logoutFailTitle": "Échec de la déconnexion",
|
||||
"logoutFailSubtitle": "Veuillez réessayer",
|
||||
"logoutSuccessTitle": "Déconnecté",
|
||||
"logoutSuccessSubtitle": "Vous avez été déconnecté",
|
||||
"logoutTitle": "Déconnexion",
|
||||
"logoutUsernameSubtitle": "Vous êtes actuellement connecté en tant que <Code>{{username}}</Code>, cliquez sur le bouton ci-dessous pour vous déconnecter.",
|
||||
"logoutOauthSubtitle": "Vous êtes actuellement connecté en tant que <Code>{{username}}</Code> en utilisant le fournisseur OAuth {{provider}} , cliquez sur le bouton ci-dessous pour vous déconnecter.",
|
||||
"notFoundTitle": "Page introuvable",
|
||||
"notFoundSubtitle": "La page recherchée n'existe pas.",
|
||||
"notFoundButton": "Retour à la page d'accueil",
|
||||
"totpFailTitle": "Échec de la vérification du code",
|
||||
"totpFailSubtitle": "Veuillez vérifier votre code et réessayer",
|
||||
"totpSuccessTitle": "Vérifié",
|
||||
"totpSuccessSubtitle": "Redirection vers votre application",
|
||||
"totpTitle": "Saisissez votre code TOTP",
|
||||
"unauthorizedTitle": "Non autorisé",
|
||||
"unauthorizedResourceSubtitle": "L'utilisateur avec le nom d'utilisateur {{username}} n'est pas autorisé à accéder à la ressource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "L'utilisateur avec le nom d'utilisateur {{username}} n'est pas autorisé à se connecter.",
|
||||
"unauthorizedButton": "Réessayer"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/he-IL.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/hu-HU.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/it-IT.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/ja-JP.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/ko-KR.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/nl-NL.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/no-NO.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/pl-PL.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Witaj ponownie, zaloguj się przez",
|
||||
"loginDivider": "Lub kontynuuj z hasłem",
|
||||
"loginUsername": "Nazwa użytkownika",
|
||||
"loginPassword": "Hasło",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Sprawdź swoją nazwę użytkownika i hasło",
|
||||
"loginSuccessTitle": "Zalogowano",
|
||||
"loginSuccessSubtitle": "Witaj ponownie!",
|
||||
"loginOauthFailTitle": "Wewnętrzny błąd",
|
||||
"loginOauthFailSubtitle": "Nie udało się uzyskać adresu URL OAuth",
|
||||
"loginOauthSuccessTitle": "Przekierowywanie",
|
||||
"loginOauthSuccessSubtitle": "Przekierowywanie do Twojego dostawcy OAuth",
|
||||
"continueRedirectingTitle": "Przekierowywanie...",
|
||||
"continueRedirectingSubtitle": "Wkrótce powinieneś zostać przekierowany do aplikacji",
|
||||
"continueInvalidRedirectTitle": "Nieprawidłowe przekierowanie",
|
||||
"continueInvalidRedirectSubtitle": "Adres przekierowania jest nieprawidłowy",
|
||||
"continueInsecureRedirectTitle": "Niezabezpieczone przekierowanie",
|
||||
"continueInsecureRedirectSubtitle": "Próbujesz przekierować z <Code>https</Code> do <Code>http</Code>, czy na pewno chcesz kontynuować?",
|
||||
"continueTitle": "Kontynuuj",
|
||||
"continueSubtitle": "Kliknij przycisk, aby przejść do aplikacji.",
|
||||
"internalErrorTitle": "Wewnętrzny błąd serwera",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Spróbuj ponownie",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Spróbuj ponownie",
|
||||
"logoutSuccessTitle": "Wylogowano",
|
||||
"logoutSuccessSubtitle": "Zostałeś wylogowany",
|
||||
"logoutTitle": "Wylogowanie",
|
||||
"logoutUsernameSubtitle": "Jesteś aktualnie zalogowany jako <Code>{{username}}</Code>, kliknij przycisk poniżej, aby się wylogować.",
|
||||
"logoutOauthSubtitle": "Jesteś obecnie zalogowany jako <Code>{{username}}</Code> przy użyciu providera OAuth {{provider}}, kliknij przycisk poniżej, aby się wylogować.",
|
||||
"notFoundTitle": "Strona nie znaleziona",
|
||||
"notFoundSubtitle": "Strona, której szukasz nie istnieje.",
|
||||
"notFoundButton": "Wróć do strony głównej",
|
||||
"totpFailTitle": "Nie udało się zweryfikować kodu",
|
||||
"totpFailSubtitle": "Sprawdź swój kod i spróbuj ponownie",
|
||||
"totpSuccessTitle": "Zweryfikowano",
|
||||
"totpSuccessSubtitle": "Przekierowywanie do aplikacji",
|
||||
"totpTitle": "Wprowadź kod TOTP",
|
||||
"unauthorizedTitle": "Nieautoryzowany",
|
||||
"unauthorizedResourceSubtitle": "Użytkownik o nazwie {{username}} nie jest upoważniony do uzyskania dostępu do zasobu <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "Użytkownik o nazwie {{username}} nie jest upoważniony do logowania.",
|
||||
"unauthorizedButton": "Spróbuj ponownie"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/pt-BR.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/pt-PT.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/ro-RO.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/ru-RU.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/sr-SP.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/sv-SE.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/tr-TR.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/uk-UA.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/vi-VN.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/zh-CN.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
45
frontend/src/lib/i18n/locales/zh-TW.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"loginTitle": "Welcome back, login with",
|
||||
"loginDivider": "Or continue with password",
|
||||
"loginUsername": "Username",
|
||||
"loginPassword": "Password",
|
||||
"loginSubmit": "Login",
|
||||
"loginFailTitle": "Failed to log in",
|
||||
"loginFailSubtitle": "Please check your username and password",
|
||||
"loginSuccessTitle": "Logged in",
|
||||
"loginSuccessSubtitle": "Welcome back!",
|
||||
"loginOauthFailTitle": "Internal error",
|
||||
"loginOauthFailSubtitle": "Failed to get OAuth URL",
|
||||
"loginOauthSuccessTitle": "Redirecting",
|
||||
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
|
||||
"continueRedirectingTitle": "Redirecting...",
|
||||
"continueRedirectingSubtitle": "You should be redirected to the app soon",
|
||||
"continueInvalidRedirectTitle": "Invalid redirect",
|
||||
"continueInvalidRedirectSubtitle": "The redirect URL is invalid",
|
||||
"continueInsecureRedirectTitle": "Insecure redirect",
|
||||
"continueInsecureRedirectSubtitle": "You are trying to redirect from <Code>https</Code> to <Code>http</Code>, are you sure you want to continue?",
|
||||
"continueTitle": "Continue",
|
||||
"continueSubtitle": "Click the button to continue to your app.",
|
||||
"internalErrorTitle": "Internal Server Error",
|
||||
"internalErrorSubtitle": "An error occurred on the server and it currently cannot serve your request.",
|
||||
"internalErrorButton": "Try again",
|
||||
"logoutFailTitle": "Failed to log out",
|
||||
"logoutFailSubtitle": "Please try again",
|
||||
"logoutSuccessTitle": "Logged out",
|
||||
"logoutSuccessSubtitle": "You have been logged out",
|
||||
"logoutTitle": "Logout",
|
||||
"logoutUsernameSubtitle": "You are currently logged in as <Code>{{username}}</Code>, click the button below to logout.",
|
||||
"logoutOauthSubtitle": "You are currently logged in as <Code>{{username}}</Code> using the {{provider}} OAuth provider, click the button below to logout.",
|
||||
"notFoundTitle": "Page not found",
|
||||
"notFoundSubtitle": "The page you are looking for does not exist.",
|
||||
"notFoundButton": "Go home",
|
||||
"totpFailTitle": "Failed to verify code",
|
||||
"totpFailSubtitle": "Please check your code and try again",
|
||||
"totpSuccessTitle": "Verified",
|
||||
"totpSuccessSubtitle": "Redirecting to your app",
|
||||
"totpTitle": "Enter your TOTP code",
|
||||
"unauthorizedTitle": "Unauthorized",
|
||||
"unauthorizedResourceSubtitle": "The user with username {{username}} is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||
"unaothorizedLoginSubtitle": "The user with username {{username}} is not authorized to login.",
|
||||
"unauthorizedButton": "Try again"
|
||||
}
|
||||
54
frontend/src/main.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { App } from "./App.tsx";
|
||||
import { MantineProvider } from "@mantine/core";
|
||||
import { Notifications } from "@mantine/notifications";
|
||||
import "@mantine/core/styles.css";
|
||||
import "@mantine/notifications/styles.css";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { BrowserRouter, Route } from "react-router";
|
||||
import { Routes } from "react-router";
|
||||
import { UserContextProvider } from "./context/user-context.tsx";
|
||||
import { LoginPage } from "./pages/login-page.tsx";
|
||||
import { LogoutPage } from "./pages/logout-page.tsx";
|
||||
import { ContinuePage } from "./pages/continue-page.tsx";
|
||||
import { NotFoundPage } from "./pages/not-found-page.tsx";
|
||||
import { UnauthorizedPage } from "./pages/unauthorized-page.tsx";
|
||||
import { InternalServerError } from "./pages/internal-server-error.tsx";
|
||||
import { TotpPage } from "./pages/totp-page.tsx";
|
||||
import { AppContextProvider } from "./context/app-context.tsx";
|
||||
import "./lib/i18n/i18n.ts";
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
suspense: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<MantineProvider forceColorScheme="dark">
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Notifications />
|
||||
<AppContextProvider>
|
||||
<UserContextProvider>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<App />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/totp" element={<TotpPage />} />
|
||||
<Route path="/logout" element={<LogoutPage />} />
|
||||
<Route path="/continue" element={<ContinuePage />} />
|
||||
<Route path="/unauthorized" element={<UnauthorizedPage />} />
|
||||
<Route path="/error" element={<InternalServerError />} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</UserContextProvider>
|
||||
</AppContextProvider>
|
||||
</QueryClientProvider>
|
||||
</MantineProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
107
frontend/src/pages/continue-page.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { Button, Code, Paper, Text } from "@mantine/core";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import { Navigate } from "react-router";
|
||||
import { useUserContext } from "../context/user-context";
|
||||
import { Layout } from "../components/layouts/layout";
|
||||
import { ReactNode } from "react";
|
||||
import { isQueryValid } from "../utils/utils";
|
||||
import { useAppContext } from "../context/app-context";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
export const ContinuePage = () => {
|
||||
const queryString = window.location.search;
|
||||
const params = new URLSearchParams(queryString);
|
||||
const redirectUri = params.get("redirect_uri") ?? "";
|
||||
|
||||
const { isLoggedIn } = useUserContext();
|
||||
const { disableContinue } = useAppContext();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
return <Navigate to={`/login?redirect_uri=${redirectUri}`} />;
|
||||
}
|
||||
|
||||
if (!isQueryValid(redirectUri)) {
|
||||
return <Navigate to="/" />;
|
||||
}
|
||||
|
||||
const redirect = () => {
|
||||
notifications.show({
|
||||
title: t("continueRedirectingTitle"),
|
||||
message: t("continueRedirectingSubtitle"),
|
||||
color: "blue",
|
||||
});
|
||||
setTimeout(() => {
|
||||
window.location.href = redirectUri;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
let uri;
|
||||
|
||||
try {
|
||||
uri = new URL(redirectUri);
|
||||
} catch {
|
||||
return (
|
||||
<ContinuePageLayout>
|
||||
<Text size="xl" fw={700}>
|
||||
{t("Invalid redirect")}
|
||||
</Text>
|
||||
<Text>{t("The redirect URL is invalid")}</Text>
|
||||
</ContinuePageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
if (disableContinue) {
|
||||
window.location.href = redirectUri;
|
||||
return (
|
||||
<ContinuePageLayout>
|
||||
<Text size="xl" fw={700}>
|
||||
{t("continueRedirectingTitle")}
|
||||
</Text>
|
||||
<Text>{t("continueRedirectingSubtitle")}</Text>
|
||||
</ContinuePageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
if (window.location.protocol === "https:" && uri.protocol === "http:") {
|
||||
return (
|
||||
<ContinuePageLayout>
|
||||
<Text size="xl" fw={700}>
|
||||
{t("continueInsecureRedirectTitle")}
|
||||
</Text>
|
||||
<Text>
|
||||
<Trans
|
||||
i18nKey="continueInsecureRedirectSubtitle"
|
||||
t={t}
|
||||
components={{ Code: <Code /> }}
|
||||
/>
|
||||
</Text>
|
||||
<Button fullWidth mt="xl" color="yellow" onClick={redirect}>
|
||||
{t("continueTitle")}
|
||||
</Button>
|
||||
</ContinuePageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ContinuePageLayout>
|
||||
<Text size="xl" fw={700}>
|
||||
{t("continueTitle")}
|
||||
</Text>
|
||||
<Text>{t("continueSubtitle")}</Text>
|
||||
<Button fullWidth mt="xl" onClick={redirect}>
|
||||
{t("continueTitle")}
|
||||
</Button>
|
||||
</ContinuePageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export const ContinuePageLayout = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<Layout>
|
||||
<Paper shadow="md" p={30} mt={30} radius="md" withBorder>
|
||||
{children}
|
||||
</Paper>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
20
frontend/src/pages/internal-server-error.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Button, Paper, Text } from "@mantine/core";
|
||||
import { Layout } from "../components/layouts/layout";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export const InternalServerError = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Layout>
|
||||
<Paper shadow="md" p={30} mt={30} radius="md" withBorder>
|
||||
<Text size="xl" fw={700}>
|
||||
{t("internalErrorTitle")}
|
||||
</Text>
|
||||
<Text>{t("internalErrorSubtitle")}</Text>
|
||||
<Button fullWidth mt="xl" onClick={() => window.location.replace("/")}>
|
||||
{t("internalErrorButton")}
|
||||
</Button>
|
||||
</Paper>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
128
frontend/src/pages/login-page.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Paper, Title, Text, Divider } from "@mantine/core";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
import { useUserContext } from "../context/user-context";
|
||||
import { Navigate } from "react-router";
|
||||
import { Layout } from "../components/layouts/layout";
|
||||
import { OAuthButtons } from "../components/auth/oauth-buttons";
|
||||
import { LoginFormValues } from "../schemas/login-schema";
|
||||
import { LoginForm } from "../components/auth/login-forn";
|
||||
import { isQueryValid } from "../utils/utils";
|
||||
import { useAppContext } from "../context/app-context";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export const LoginPage = () => {
|
||||
const queryString = window.location.search;
|
||||
const params = new URLSearchParams(queryString);
|
||||
const redirectUri = params.get("redirect_uri") ?? "";
|
||||
|
||||
const { isLoggedIn } = useUserContext();
|
||||
const { configuredProviders, title, genericName } = useAppContext();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const oauthProviders = configuredProviders.filter(
|
||||
(value) => value !== "username",
|
||||
);
|
||||
|
||||
if (isLoggedIn) {
|
||||
return <Navigate to="/logout" />;
|
||||
}
|
||||
|
||||
const loginMutation = useMutation({
|
||||
mutationFn: (login: LoginFormValues) => {
|
||||
return axios.post("/api/login", login);
|
||||
},
|
||||
onError: () => {
|
||||
notifications.show({
|
||||
title: t("loginFailTitle"),
|
||||
message: t("loginFailSubtitle"),
|
||||
color: "red",
|
||||
});
|
||||
},
|
||||
onSuccess: async (data) => {
|
||||
if (data.data.totpPending) {
|
||||
window.location.replace(`/totp?redirect_uri=${redirectUri}`);
|
||||
return;
|
||||
}
|
||||
|
||||
notifications.show({
|
||||
title: t("loginSuccessTitle"),
|
||||
message: t("loginSuccessSubtitle"),
|
||||
color: "green",
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
if (!isQueryValid(redirectUri)) {
|
||||
window.location.replace("/");
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.replace(`/continue?redirect_uri=${redirectUri}`);
|
||||
}, 500);
|
||||
},
|
||||
});
|
||||
|
||||
const loginOAuthMutation = useMutation({
|
||||
mutationFn: (provider: string) => {
|
||||
return axios.get(
|
||||
`/api/oauth/url/${provider}?redirect_uri=${redirectUri}`,
|
||||
);
|
||||
},
|
||||
onError: () => {
|
||||
notifications.show({
|
||||
title: t("loginOauthFailTitle"),
|
||||
message: t("loginOauthFailSubtitle"),
|
||||
color: "red",
|
||||
});
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
notifications.show({
|
||||
title: t("loginOauthSuccessTitle"),
|
||||
message: t("loginOauthSuccessSubtitle"),
|
||||
color: "blue",
|
||||
});
|
||||
setTimeout(() => {
|
||||
window.location.href = data.data.url;
|
||||
}, 500);
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit = (values: LoginFormValues) => {
|
||||
loginMutation.mutate(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Title ta="center">{title}</Title>
|
||||
<Paper shadow="md" p="xl" mt={30} radius="md" withBorder>
|
||||
{oauthProviders.length > 0 && (
|
||||
<>
|
||||
<Text size="lg" fw={500} ta="center">
|
||||
{t("loginTitle")}
|
||||
</Text>
|
||||
<OAuthButtons
|
||||
oauthProviders={oauthProviders}
|
||||
isLoading={loginOAuthMutation.isLoading}
|
||||
mutate={loginOAuthMutation.mutate}
|
||||
genericName={genericName}
|
||||
/>
|
||||
{configuredProviders.includes("username") && (
|
||||
<Divider
|
||||
label={t("loginDivider")}
|
||||
labelPosition="center"
|
||||
my="lg"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{configuredProviders.includes("username") && (
|
||||
<LoginForm
|
||||
isLoading={loginMutation.isLoading}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
)}
|
||||
</Paper>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
84
frontend/src/pages/logout-page.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import { Button, Code, Paper, Text } from "@mantine/core";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
import { useUserContext } from "../context/user-context";
|
||||
import { Navigate } from "react-router";
|
||||
import { Layout } from "../components/layouts/layout";
|
||||
import { capitalize } from "../utils/utils";
|
||||
import { useAppContext } from "../context/app-context";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
export const LogoutPage = () => {
|
||||
const { isLoggedIn, username, oauth, provider } = useUserContext();
|
||||
const { genericName } = useAppContext();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
return <Navigate to="/login" />;
|
||||
}
|
||||
|
||||
const logoutMutation = useMutation({
|
||||
mutationFn: () => {
|
||||
return axios.post("/api/logout");
|
||||
},
|
||||
onError: () => {
|
||||
notifications.show({
|
||||
title: t("logoutFailTitle"),
|
||||
message: t("logoutFailSubtitle"),
|
||||
color: "red",
|
||||
});
|
||||
},
|
||||
onSuccess: () => {
|
||||
notifications.show({
|
||||
title: t("logoutSuccessTitle"),
|
||||
message: t("logoutSuccessSubtitle"),
|
||||
color: "green",
|
||||
});
|
||||
setTimeout(() => {
|
||||
window.location.replace("/login");
|
||||
}, 500);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Paper shadow="md" p={30} mt={30} radius="md" withBorder>
|
||||
<Text size="xl" fw={700}>
|
||||
{t("logoutTitle")}
|
||||
</Text>
|
||||
<Text>
|
||||
{oauth ? (
|
||||
<Trans
|
||||
i18nKey="logoutOauthSubtitle"
|
||||
t={t}
|
||||
components={{ Code: <Code /> }}
|
||||
values={{
|
||||
provider:
|
||||
provider === "generic" ? genericName : capitalize(provider),
|
||||
username: username,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey="logoutUsernameSubtitle"
|
||||
t={t}
|
||||
components={{ Code: <Code /> }}
|
||||
values={{
|
||||
username: username,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Text>
|
||||
<Button
|
||||
fullWidth
|
||||
mt="xl"
|
||||
onClick={() => logoutMutation.mutate()}
|
||||
loading={logoutMutation.isLoading}
|
||||
>
|
||||
{t("logoutTitle")}
|
||||
</Button>
|
||||
</Paper>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
20
frontend/src/pages/not-found-page.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Button, Paper, Text } from "@mantine/core";
|
||||
import { Layout } from "../components/layouts/layout";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export const NotFoundPage = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Layout>
|
||||
<Paper shadow="md" p={30} mt={30} radius="md" withBorder>
|
||||
<Text size="xl" fw={700}>
|
||||
{t("notFoundTitle")}
|
||||
</Text>
|
||||
<Text>{t("notFoundSubtitle")}</Text>
|
||||
<Button fullWidth mt="xl" onClick={() => window.location.replace("/")}>
|
||||
{t("notFoundButton")}
|
||||
</Button>
|
||||
</Paper>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
66
frontend/src/pages/totp-page.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Navigate } from "react-router";
|
||||
import { useUserContext } from "../context/user-context";
|
||||
import { Title, Paper, Text } from "@mantine/core";
|
||||
import { Layout } from "../components/layouts/layout";
|
||||
import { TotpForm } from "../components/auth/totp-form";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import { useAppContext } from "../context/app-context";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export const TotpPage = () => {
|
||||
const queryString = window.location.search;
|
||||
const params = new URLSearchParams(queryString);
|
||||
const redirectUri = params.get("redirect_uri") ?? "";
|
||||
|
||||
const { totpPending, isLoggedIn } = useUserContext();
|
||||
const { title } = useAppContext();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (isLoggedIn) {
|
||||
return <Navigate to={`/logout`} />;
|
||||
}
|
||||
|
||||
if (!totpPending) {
|
||||
return <Navigate to={`/login?redirect_uri=${redirectUri}`} />;
|
||||
}
|
||||
|
||||
const totpMutation = useMutation({
|
||||
mutationFn: async (totp: { code: string }) => {
|
||||
await axios.post("/api/totp", totp);
|
||||
},
|
||||
onError: () => {
|
||||
notifications.show({
|
||||
title: t("totpFailTitle"),
|
||||
message: t("totpFailSubtitle"),
|
||||
color: "red",
|
||||
});
|
||||
},
|
||||
onSuccess: () => {
|
||||
notifications.show({
|
||||
title: t("totpSuccessTitle"),
|
||||
message: t("totpSuccessSubtitle"),
|
||||
color: "green",
|
||||
});
|
||||
setTimeout(() => {
|
||||
window.location.replace(`/continue?redirect_uri=${redirectUri}`);
|
||||
}, 500);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Title ta="center">{title}</Title>
|
||||
<Paper shadow="md" p="xl" mt={30} radius="md" withBorder>
|
||||
<Text size="lg" fw={500} mb="md" ta="center">
|
||||
{t("totpTitle")}
|
||||
</Text>
|
||||
<TotpForm
|
||||
isLoading={totpMutation.isLoading}
|
||||
onSubmit={(values) => totpMutation.mutate(values)}
|
||||
/>
|
||||
</Paper>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
55
frontend/src/pages/unauthorized-page.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Button, Code, Paper, Text } from "@mantine/core";
|
||||
import { Layout } from "../components/layouts/layout";
|
||||
import { Navigate } from "react-router";
|
||||
import { isQueryValid } from "../utils/utils";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
export const UnauthorizedPage = () => {
|
||||
const queryString = window.location.search;
|
||||
const params = new URLSearchParams(queryString);
|
||||
const username = params.get("username") ?? "";
|
||||
const resource = params.get("resource") ?? "";
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!isQueryValid(username)) {
|
||||
return <Navigate to="/" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Paper shadow="md" p={30} mt={30} radius="md" withBorder>
|
||||
<Text size="xl" fw={700}>
|
||||
{t("Unauthorized")}
|
||||
</Text>
|
||||
<Text>
|
||||
{isQueryValid(resource) ? (
|
||||
<Text>
|
||||
<Trans
|
||||
i18nKey="unauthorizedResourceSubtitle"
|
||||
t={t}
|
||||
components={{ Code: <Code /> }}
|
||||
values={{ resource, username }}
|
||||
/>
|
||||
</Text>
|
||||
) : (
|
||||
<Text>
|
||||
<Trans
|
||||
i18nKey="unauthorizedLoginSubtitle"
|
||||
t={t}
|
||||
values={{ username }}
|
||||
/>
|
||||
</Text>
|
||||
)}
|
||||
</Text>
|
||||
<Button
|
||||
fullWidth
|
||||
mt="xl"
|
||||
onClick={() => window.location.replace("/login")}
|
||||
>
|
||||
{t("unauthorizedButton")}
|
||||
</Button>
|
||||
</Paper>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
10
frontend/src/schemas/app-context-schema.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const appContextSchema = z.object({
|
||||
configuredProviders: z.array(z.string()),
|
||||
disableContinue: z.boolean(),
|
||||
title: z.string(),
|
||||
genericName: z.string(),
|
||||
});
|
||||
|
||||
export type AppContextSchemaType = z.infer<typeof appContextSchema>;
|
||||
8
frontend/src/schemas/login-schema.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const loginSchema = z.object({
|
||||
username: z.string(),
|
||||
password: z.string(),
|
||||
});
|
||||
|
||||
export type LoginFormValues = z.infer<typeof loginSchema>;
|
||||
11
frontend/src/schemas/user-context-schema.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const userContextSchema = z.object({
|
||||
isLoggedIn: z.boolean(),
|
||||
username: z.string(),
|
||||
oauth: z.boolean(),
|
||||
provider: z.string(),
|
||||
totpPending: z.boolean(),
|
||||
});
|
||||
|
||||
export type UserContextSchemaType = z.infer<typeof userContextSchema>;
|
||||
2
frontend/src/utils/utils.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
|
||||
export const isQueryValid = (value: string) => value.trim() !== "" && value !== "null";
|
||||
1
frontend/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
26
frontend/tsconfig.app.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
7
frontend/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
24
frontend/tsconfig.node.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
17
frontend/vite.config.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
host: "0.0.0.0",
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: "http://tinyauth-backend:3000/api",
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ""),
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||