mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-08-28 03:30:05 +00:00
Added more languages and picker
This commit is contained in:
@@ -63,7 +63,7 @@
|
|||||||
"format": "yarn prettier -- --write",
|
"format": "yarn prettier -- --write",
|
||||||
"lint:fix": "eslint --fix --ext .ts --ext .tsx .",
|
"lint:fix": "eslint --fix --ext .ts --ext .tsx .",
|
||||||
"locale-extract": "formatjs extract 'src/**/*.tsx' --out-file src/locale/src/en.json",
|
"locale-extract": "formatjs extract 'src/**/*.tsx' --out-file src/locale/src/en.json",
|
||||||
"locale-compile": "formatjs compile-folder src/locale/src src/locale/lang --ast"
|
"locale-compile": "formatjs compile-folder src/locale/src src/locale/lang"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
|
@@ -55,6 +55,10 @@
|
|||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://unpkg.com/@tabler/core@1.0.0-beta3/dist/css/tabler.min.css"
|
href="https://unpkg.com/@tabler/core@1.0.0-beta3/dist/css/tabler.min.css"
|
||||||
/>
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://unpkg.com/@tabler/core@1.0.0-beta3/dist/css/tabler-flags.min.css"
|
||||||
|
/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
@@ -1,18 +1,20 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Router from "components/Router";
|
import Router from "components/Router";
|
||||||
import { AuthProvider, HealthProvider } from "context";
|
import { AuthProvider, HealthProvider, LocaleProvider } from "context";
|
||||||
import { intl } from "locale";
|
import { intl } from "locale";
|
||||||
import { RawIntlProvider } from "react-intl";
|
import { RawIntlProvider } from "react-intl";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<RawIntlProvider value={intl}>
|
<RawIntlProvider value={intl}>
|
||||||
<HealthProvider>
|
<LocaleProvider>
|
||||||
<AuthProvider>
|
<HealthProvider>
|
||||||
<Router />
|
<AuthProvider>
|
||||||
</AuthProvider>
|
<Router />
|
||||||
</HealthProvider>
|
</AuthProvider>
|
||||||
|
</HealthProvider>
|
||||||
|
</LocaleProvider>
|
||||||
</RawIntlProvider>
|
</RawIntlProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -45,6 +45,7 @@ export const DropdownItem: React.FC<DropdownItemProps> = ({
|
|||||||
icon,
|
icon,
|
||||||
href,
|
href,
|
||||||
onClick,
|
onClick,
|
||||||
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
return divider ? (
|
return divider ? (
|
||||||
<div className={cn("dropdown-divider", className)} />
|
<div className={cn("dropdown-divider", className)} />
|
||||||
@@ -57,7 +58,8 @@ export const DropdownItem: React.FC<DropdownItemProps> = ({
|
|||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
href={href}
|
href={href}
|
||||||
onClick={onClick}>
|
onClick={onClick}
|
||||||
|
{...rest}>
|
||||||
{icon && <span className="dropdown-item-icon">{icon}</span>}
|
{icon && <span className="dropdown-item-icon">{icon}</span>}
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
|
28
frontend/src/components/Flag/Flag.tsx
Normal file
28
frontend/src/components/Flag/Flag.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import cn from "classnames";
|
||||||
|
|
||||||
|
export interface FlagProps {
|
||||||
|
/**
|
||||||
|
* Additional Class
|
||||||
|
*/
|
||||||
|
className?: string;
|
||||||
|
/**
|
||||||
|
* Country code of flag
|
||||||
|
*/
|
||||||
|
country: string;
|
||||||
|
/**
|
||||||
|
* Size of the flag
|
||||||
|
*/
|
||||||
|
size?: string;
|
||||||
|
}
|
||||||
|
export const Flag: React.FC<FlagProps> = ({ className, country, size }) => {
|
||||||
|
const classes = [
|
||||||
|
`flag-country-${country.toLowerCase()}`,
|
||||||
|
{
|
||||||
|
[`flag-${size}`]: !!size,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return <span className={cn("flag", classes, className)} />;
|
||||||
|
};
|
1
frontend/src/components/Flag/index.ts
Normal file
1
frontend/src/components/Flag/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./Flag";
|
67
frontend/src/components/LocalePicker.tsx
Normal file
67
frontend/src/components/LocalePicker.tsx
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
import { Button, Dropdown, Flag } from "components";
|
||||||
|
import { useLocaleState } from "context";
|
||||||
|
import { changeLocale, getFlagCodeForLocale, getLocale, intl } from "locale";
|
||||||
|
|
||||||
|
export interface LocalPickerProps {
|
||||||
|
/**
|
||||||
|
* On click handler
|
||||||
|
*/
|
||||||
|
onChange?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LocalePicker: React.FC<LocalPickerProps> = ({
|
||||||
|
onChange,
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
|
const { locale, setLocale } = useLocaleState();
|
||||||
|
|
||||||
|
// const [locale, setLocale] = useState(getLocale());
|
||||||
|
const [localeShown, setLocaleShown] = useState(false);
|
||||||
|
|
||||||
|
const handleOnChange = (e: any) => {
|
||||||
|
changeLocale(e.currentTarget.rel);
|
||||||
|
setLocale(e.currentTarget.rel);
|
||||||
|
setLocaleShown(false);
|
||||||
|
onChange && onChange(locale);
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
["us", "en-US"],
|
||||||
|
["de", "de-DE"],
|
||||||
|
["ir", "fa-IR"],
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dropdown" {...rest}>
|
||||||
|
<Button
|
||||||
|
shape="ghost"
|
||||||
|
onClick={(e: any) => {
|
||||||
|
setLocaleShown(!localeShown);
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
iconOnly>
|
||||||
|
<Flag country={getFlagCodeForLocale(locale)} />
|
||||||
|
</Button>
|
||||||
|
<Dropdown
|
||||||
|
className="dropdown-menu-end dropdown-menu-card"
|
||||||
|
show={localeShown}>
|
||||||
|
{options.map((item) => {
|
||||||
|
return (
|
||||||
|
<Dropdown.Item
|
||||||
|
key={`locale-${item[0]}`}
|
||||||
|
rel={item[1]}
|
||||||
|
icon={<Flag country={item[0]} />}
|
||||||
|
onClick={handleOnChange}>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: `locale-${item[1]}`,
|
||||||
|
defaultMessage: item[1],
|
||||||
|
})}
|
||||||
|
</Dropdown.Item>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@@ -2,9 +2,9 @@ import React, { ReactNode } from "react";
|
|||||||
|
|
||||||
import { Footer } from "components";
|
import { Footer } from "components";
|
||||||
import { Avatar, Dropdown, Navigation } from "components";
|
import { Avatar, Dropdown, Navigation } from "components";
|
||||||
|
import { LocalePicker } from "components";
|
||||||
import { useAuthState, useUserState } from "context";
|
import { useAuthState, useUserState } from "context";
|
||||||
import { intl } from "locale";
|
import { intl } from "locale";
|
||||||
import { FormattedMessage } from "react-intl";
|
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { NavMenu } from "./NavMenu";
|
import { NavMenu } from "./NavMenu";
|
||||||
@@ -45,16 +45,20 @@ function SiteWrapper({ children }: Props) {
|
|||||||
defaultMessage: "Standard User",
|
defaultMessage: "Standard User",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
buttons={[<LocalePicker key="lp1" />]}
|
||||||
profileItems={[
|
profileItems={[
|
||||||
<Dropdown.Item key="m1-2">
|
<Dropdown.Item key="m1-2">
|
||||||
<FormattedMessage
|
{intl.formatMessage({
|
||||||
id="profile.title"
|
id: "profile.title",
|
||||||
defaultMessage="Profile settings"
|
defaultMessage: "Profile settings",
|
||||||
/>
|
})}
|
||||||
</Dropdown.Item>,
|
</Dropdown.Item>,
|
||||||
<Dropdown.Item divider key="m1-4" />,
|
<Dropdown.Item divider key="m1-4" />,
|
||||||
<Dropdown.Item key="m1-6" onClick={logout}>
|
<Dropdown.Item key="m1-6" onClick={logout}>
|
||||||
<FormattedMessage id="profile.logout" defaultMessage="Logout" />
|
{intl.formatMessage({
|
||||||
|
id: "profile.logout",
|
||||||
|
defaultMessage: "Logout",
|
||||||
|
})}
|
||||||
</Dropdown.Item>,
|
</Dropdown.Item>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
@@ -5,9 +5,11 @@ export * from "./Badge";
|
|||||||
export * from "./Button";
|
export * from "./Button";
|
||||||
export * from "./ButtonList";
|
export * from "./ButtonList";
|
||||||
export * from "./Dropdown";
|
export * from "./Dropdown";
|
||||||
|
export * from "./Flag";
|
||||||
export * from "./Footer";
|
export * from "./Footer";
|
||||||
export * from "./Loader";
|
export * from "./Loader";
|
||||||
export * from "./Loading";
|
export * from "./Loading";
|
||||||
|
export * from "./LocalePicker";
|
||||||
export * from "./Navigation";
|
export * from "./Navigation";
|
||||||
export * from "./NavMenu";
|
export * from "./NavMenu";
|
||||||
export * from "./Router";
|
export * from "./Router";
|
||||||
|
43
frontend/src/context/LocaleContext.tsx
Normal file
43
frontend/src/context/LocaleContext.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import React, { ReactNode, useState } from "react";
|
||||||
|
|
||||||
|
import { getLocale } from "locale";
|
||||||
|
|
||||||
|
// Context
|
||||||
|
export interface LocaleContextType {
|
||||||
|
setLocale: (locale: string) => void;
|
||||||
|
locale?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initalValue = null;
|
||||||
|
const LocaleContext = React.createContext<LocaleContextType | null>(
|
||||||
|
initalValue,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Provider
|
||||||
|
interface Props {
|
||||||
|
children?: ReactNode;
|
||||||
|
}
|
||||||
|
function LocaleProvider({ children }: Props) {
|
||||||
|
const [locale, setLocaleValue] = useState(getLocale());
|
||||||
|
|
||||||
|
const setLocale = async (locale: string) => {
|
||||||
|
setLocaleValue(locale);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = { locale, setLocale };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useLocaleState() {
|
||||||
|
const context = React.useContext(LocaleContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(`useLocaleState must be used within a LocaleProvider`);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { LocaleProvider, useLocaleState };
|
||||||
|
export default LocaleContext;
|
@@ -1,3 +1,4 @@
|
|||||||
export * from "./AuthContext";
|
export * from "./AuthContext";
|
||||||
export * from "./HealthContext";
|
export * from "./HealthContext";
|
||||||
|
export * from "./LocaleContext";
|
||||||
export * from "./UserContext";
|
export * from "./UserContext";
|
||||||
|
@@ -1,25 +1,53 @@
|
|||||||
import { createIntl, createIntlCache } from "react-intl";
|
import { createIntl, createIntlCache } from "react-intl";
|
||||||
|
|
||||||
|
import langDe from "./lang/de.json";
|
||||||
import langEn from "./lang/en.json";
|
import langEn from "./lang/en.json";
|
||||||
|
import langFa from "./lang/fa.json";
|
||||||
|
|
||||||
const loadMessages = (locale: string) => {
|
const loadMessages = (locale?: string) => {
|
||||||
switch (locale) {
|
locale = locale || "en";
|
||||||
/*
|
switch (locale.substr(0, 2)) {
|
||||||
case 'fr':
|
case "de":
|
||||||
return import("./lang/fr.json");
|
return Object.assign({}, langEn, langDe);
|
||||||
*/
|
case "fa":
|
||||||
|
return Object.assign({}, langEn, langFa);
|
||||||
default:
|
default:
|
||||||
return langEn;
|
return langEn;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initialLocale = "en-US";
|
export const getFlagCodeForLocale = (locale?: string) => {
|
||||||
export const cache = createIntlCache();
|
switch (locale) {
|
||||||
|
case "de-DE":
|
||||||
|
case "de":
|
||||||
|
return "de";
|
||||||
|
case "fa-IR":
|
||||||
|
case "fa":
|
||||||
|
return "ir";
|
||||||
|
default:
|
||||||
|
return "us";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const initialMessages = loadMessages(initialLocale);
|
export const getLocale = () => {
|
||||||
|
let loc = window.localStorage.getItem("locale");
|
||||||
|
if (!loc) {
|
||||||
|
loc = document.documentElement.lang;
|
||||||
|
}
|
||||||
|
return loc;
|
||||||
|
};
|
||||||
|
|
||||||
export const intl = createIntl(
|
const cache = createIntlCache();
|
||||||
// @ts-ignore messages file typings are correct
|
|
||||||
{ locale: initialLocale, messages: initialMessages },
|
const initialMessages = loadMessages(getLocale());
|
||||||
|
export let intl = createIntl(
|
||||||
|
{ locale: getLocale(), messages: initialMessages },
|
||||||
cache,
|
cache,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const changeLocale = (locale: string): void => {
|
||||||
|
const messages = loadMessages(locale);
|
||||||
|
intl = createIntl({ locale, messages }, cache);
|
||||||
|
window.localStorage.setItem("locale", locale);
|
||||||
|
document.documentElement.lang = locale;
|
||||||
|
};
|
||||||
|
20
frontend/src/locale/src/de.json
Normal file
20
frontend/src/locale/src/de.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"accesslists.title": {
|
||||||
|
"defaultMessage": "Zugriffslisten"
|
||||||
|
},
|
||||||
|
"auditlog.title": {
|
||||||
|
"defaultMessage": "Audit-Log"
|
||||||
|
},
|
||||||
|
"setup.create": {
|
||||||
|
"defaultMessage": "Benutzerkonto erstellen"
|
||||||
|
},
|
||||||
|
"setup.title": {
|
||||||
|
"defaultMessage": "Erstellen Sie Ihr erstes Konto"
|
||||||
|
},
|
||||||
|
"user.nickname": {
|
||||||
|
"defaultMessage": "Spitzname"
|
||||||
|
},
|
||||||
|
"user.password": {
|
||||||
|
"defaultMessage": "Passwort"
|
||||||
|
}
|
||||||
|
}
|
@@ -1,80 +1,89 @@
|
|||||||
{
|
{
|
||||||
"accesslists.title": {
|
"accesslists.title": {
|
||||||
"defaultMessage": "Access Lists"
|
"defaultMessage": "Access Lists"
|
||||||
},
|
},
|
||||||
"auditlog.title": {
|
"auditlog.title": {
|
||||||
"defaultMessage": "Audit Log"
|
"defaultMessage": "Audit Log"
|
||||||
},
|
},
|
||||||
"certificates.title": {
|
"certificates.title": {
|
||||||
"defaultMessage": "Certificates"
|
"defaultMessage": "Certificates"
|
||||||
},
|
},
|
||||||
"column.description": {
|
"column.description": {
|
||||||
"defaultMessage": "Description"
|
"defaultMessage": "Description"
|
||||||
},
|
},
|
||||||
"column.id": {
|
"column.id": {
|
||||||
"defaultMessage": "ID"
|
"defaultMessage": "ID"
|
||||||
},
|
},
|
||||||
"column.name": {
|
"column.name": {
|
||||||
"defaultMessage": "Name"
|
"defaultMessage": "Name"
|
||||||
},
|
},
|
||||||
"dashboard.title": {
|
"dashboard.title": {
|
||||||
"defaultMessage": "Dashboard"
|
"defaultMessage": "Dashboard"
|
||||||
},
|
},
|
||||||
"footer.changelog": {
|
"footer.changelog": {
|
||||||
"defaultMessage": "Change Log"
|
"defaultMessage": "Change Log"
|
||||||
},
|
},
|
||||||
"footer.copyright": {
|
"footer.copyright": {
|
||||||
"defaultMessage": "Copyright © {year} jc21.com."
|
"defaultMessage": "Copyright © {year} jc21.com."
|
||||||
},
|
},
|
||||||
"footer.github": {
|
"footer.github": {
|
||||||
"defaultMessage": "Github"
|
"defaultMessage": "Github"
|
||||||
},
|
},
|
||||||
"footer.theme": {
|
"footer.theme": {
|
||||||
"defaultMessage": "Theme by Tabler"
|
"defaultMessage": "Theme by Tabler"
|
||||||
},
|
},
|
||||||
"footer.userguide": {
|
"footer.userguide": {
|
||||||
"defaultMessage": "User Guide"
|
"defaultMessage": "User Guide"
|
||||||
},
|
},
|
||||||
"hosts.title": {
|
"hosts.title": {
|
||||||
"defaultMessage": "Hosts"
|
"defaultMessage": "Hosts"
|
||||||
},
|
},
|
||||||
"login.login": {
|
"locale-de-DE": {
|
||||||
"defaultMessage": "Sign in"
|
"defaultMessage": "Deutsche"
|
||||||
},
|
},
|
||||||
"profile.logout": {
|
"locale-en-US": {
|
||||||
"defaultMessage": "Logout"
|
"defaultMessage": "English"
|
||||||
},
|
},
|
||||||
"profile.title": {
|
"locale-fa-IR": {
|
||||||
"defaultMessage": "Profile settings"
|
"defaultMessage": "Persian"
|
||||||
},
|
},
|
||||||
"settings.title": {
|
"login.login": {
|
||||||
"defaultMessage": "Settings"
|
"defaultMessage": "Sign in"
|
||||||
},
|
},
|
||||||
"setup.create": {
|
"profile.logout": {
|
||||||
"defaultMessage": "Create Account"
|
"defaultMessage": "Logout"
|
||||||
},
|
},
|
||||||
"setup.title": {
|
"profile.title": {
|
||||||
"defaultMessage": "Create your first Account"
|
"defaultMessage": "Profile settings"
|
||||||
},
|
},
|
||||||
"user.email": {
|
"settings.title": {
|
||||||
"defaultMessage": "Email"
|
"defaultMessage": "Settings"
|
||||||
},
|
},
|
||||||
"user.name": {
|
"setup.create": {
|
||||||
"defaultMessage": "Name"
|
"defaultMessage": "Sign up"
|
||||||
},
|
},
|
||||||
"user.nickname": {
|
"setup.title": {
|
||||||
"defaultMessage": "Nickname"
|
"defaultMessage": "Create your first Account"
|
||||||
},
|
},
|
||||||
"user.password": {
|
"user.email": {
|
||||||
"defaultMessage": "Password"
|
"defaultMessage": "Email"
|
||||||
},
|
},
|
||||||
"users.admin": {
|
"user.name": {
|
||||||
"defaultMessage": "Administrator"
|
"defaultMessage": "Name"
|
||||||
},
|
},
|
||||||
"users.standard": {
|
"user.nickname": {
|
||||||
"defaultMessage": "Standard User"
|
"defaultMessage": "Nickname"
|
||||||
},
|
},
|
||||||
"users.title": {
|
"user.password": {
|
||||||
"defaultMessage": "Users"
|
"defaultMessage": "Password"
|
||||||
}
|
},
|
||||||
|
"users.admin": {
|
||||||
|
"defaultMessage": "Administrator"
|
||||||
|
},
|
||||||
|
"users.standard": {
|
||||||
|
"defaultMessage": "Standard User"
|
||||||
|
},
|
||||||
|
"users.title": {
|
||||||
|
"defaultMessage": "Users"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
77
frontend/src/locale/src/fa.json
Normal file
77
frontend/src/locale/src/fa.json
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"accesslists.title": {
|
||||||
|
"defaultMessage": "دسترسی به لیست ها"
|
||||||
|
},
|
||||||
|
"auditlog.title": {
|
||||||
|
"defaultMessage": "گزارش حسابرسی"
|
||||||
|
},
|
||||||
|
"certificates.title": {
|
||||||
|
"defaultMessage": "گواهینامه ها"
|
||||||
|
},
|
||||||
|
"column.description": {
|
||||||
|
"defaultMessage": "شرح"
|
||||||
|
},
|
||||||
|
"column.id": {
|
||||||
|
"defaultMessage": "شناسه"
|
||||||
|
},
|
||||||
|
"column.name": {
|
||||||
|
"defaultMessage": "نام"
|
||||||
|
},
|
||||||
|
"dashboard.title": {
|
||||||
|
"defaultMessage": "داشبورد"
|
||||||
|
},
|
||||||
|
"footer.changelog": {
|
||||||
|
"defaultMessage": "ورود به سیستم را تغییر دهید"
|
||||||
|
},
|
||||||
|
"footer.copyright": {
|
||||||
|
"defaultMessage": "حق چاپ © حق چاپ © {year} jc21.com"
|
||||||
|
},
|
||||||
|
"footer.theme": {
|
||||||
|
"defaultMessage": "قالب توسط Tabler"
|
||||||
|
},
|
||||||
|
"footer.userguide": {
|
||||||
|
"defaultMessage": "راهنمای کاربر"
|
||||||
|
},
|
||||||
|
"hosts.title": {
|
||||||
|
"defaultMessage": "میزبان"
|
||||||
|
},
|
||||||
|
"login.login": {
|
||||||
|
"defaultMessage": "ورود"
|
||||||
|
},
|
||||||
|
"profile.logout": {
|
||||||
|
"defaultMessage": "خروج"
|
||||||
|
},
|
||||||
|
"profile.title": {
|
||||||
|
"defaultMessage": "تنظیمات نمایه"
|
||||||
|
},
|
||||||
|
"settings.title": {
|
||||||
|
"defaultMessage": "تنظیمات"
|
||||||
|
},
|
||||||
|
"setup.create": {
|
||||||
|
"defaultMessage": "ثبت نام"
|
||||||
|
},
|
||||||
|
"setup.title": {
|
||||||
|
"defaultMessage": "اولین حساب خود را ایجاد کنید"
|
||||||
|
},
|
||||||
|
"user.email": {
|
||||||
|
"defaultMessage": "پست الکترونیک"
|
||||||
|
},
|
||||||
|
"user.name": {
|
||||||
|
"defaultMessage": "نام"
|
||||||
|
},
|
||||||
|
"user.nickname": {
|
||||||
|
"defaultMessage": "کنیه"
|
||||||
|
},
|
||||||
|
"user.password": {
|
||||||
|
"defaultMessage": "کلمه عبور"
|
||||||
|
},
|
||||||
|
"users.admin": {
|
||||||
|
"defaultMessage": "مدیر"
|
||||||
|
},
|
||||||
|
"users.standard": {
|
||||||
|
"defaultMessage": "کاربر استاندارد"
|
||||||
|
},
|
||||||
|
"users.title": {
|
||||||
|
"defaultMessage": "کاربران"
|
||||||
|
}
|
||||||
|
}
|
@@ -2,9 +2,9 @@ import React, { useEffect, useRef, useState, ChangeEvent } from "react";
|
|||||||
|
|
||||||
import { createUser } from "api/npm";
|
import { createUser } from "api/npm";
|
||||||
import { Alert, Button } from "components";
|
import { Alert, Button } from "components";
|
||||||
|
import { LocalePicker } from "components";
|
||||||
import { useAuthState, useHealthState } from "context";
|
import { useAuthState, useHealthState } from "context";
|
||||||
import { intl } from "locale";
|
import { intl } from "locale";
|
||||||
import { FormattedMessage } from "react-intl";
|
|
||||||
|
|
||||||
import logo from "../../img/logo-text-vertical-grey.png";
|
import logo from "../../img/logo-text-vertical-grey.png";
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@ function Setup() {
|
|||||||
const { refreshHealth } = useHealthState();
|
const { refreshHealth } = useHealthState();
|
||||||
const { login } = useAuthState();
|
const { login } = useAuthState();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [renderCount, setRenderCount] = useState(0);
|
||||||
const [errorMessage, setErrorMessage] = useState("");
|
const [errorMessage, setErrorMessage] = useState("");
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
@@ -82,12 +83,24 @@ function Setup() {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onSubmit={onSubmit}>
|
onSubmit={onSubmit}>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h2 className="card-title text-center mb-4">
|
<div className="row mb-4">
|
||||||
<FormattedMessage
|
<div className="col">
|
||||||
id="setup.title"
|
<h2 className="card-title">
|
||||||
defaultMessage="Create your first Account"
|
{intl.formatMessage({
|
||||||
/>
|
id: "setup.title",
|
||||||
</h2>
|
defaultMessage: "Create your first Account",
|
||||||
|
})}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div className="col col-md-2">
|
||||||
|
<LocalePicker
|
||||||
|
onChange={() => {
|
||||||
|
setRenderCount(renderCount + 1);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{errorMessage ? (
|
{errorMessage ? (
|
||||||
<Alert type="danger" className="text-center">
|
<Alert type="danger" className="text-center">
|
||||||
{errorMessage}
|
{errorMessage}
|
||||||
@@ -96,7 +109,10 @@ function Setup() {
|
|||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">
|
<label className="form-label">
|
||||||
<FormattedMessage id="user.name" defaultMessage="Name" />
|
{intl.formatMessage({
|
||||||
|
id: "user.name",
|
||||||
|
defaultMessage: "Name",
|
||||||
|
})}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
ref={nameRef}
|
ref={nameRef}
|
||||||
@@ -114,10 +130,10 @@ function Setup() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">
|
<label className="form-label">
|
||||||
<FormattedMessage
|
{intl.formatMessage({
|
||||||
id="user.nickname"
|
id: "user.nickname",
|
||||||
defaultMessage="Nickname"
|
defaultMessage: "Nickname",
|
||||||
/>
|
})}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
@@ -134,7 +150,10 @@ function Setup() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">
|
<label className="form-label">
|
||||||
<FormattedMessage id="user.email" defaultMessage="Email" />
|
{intl.formatMessage({
|
||||||
|
id: "user.email",
|
||||||
|
defaultMessage: "Email",
|
||||||
|
})}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
@@ -153,10 +172,10 @@ function Setup() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">
|
<label className="form-label">
|
||||||
<FormattedMessage
|
{intl.formatMessage({
|
||||||
id="user.password"
|
id: "user.password",
|
||||||
defaultMessage="Password"
|
defaultMessage: "Password",
|
||||||
/>
|
})}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
@@ -177,10 +196,10 @@ function Setup() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="form-footer">
|
<div className="form-footer">
|
||||||
<Button color="cyan" loading={loading} className="w-100">
|
<Button color="cyan" loading={loading} className="w-100">
|
||||||
<FormattedMessage
|
{intl.formatMessage({
|
||||||
id="setup.create"
|
id: "setup.create",
|
||||||
defaultMessage="Create Account"
|
defaultMessage: "Create Account",
|
||||||
/>
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user