1
Fork 0
mirror of https://github.com/pds-nest/nest.git synced 2024-11-22 04:54:18 +00:00

Use custom localization system

This commit is contained in:
Steffo 2021-05-18 02:04:06 +02:00
parent c0e87fb6ba
commit 20f60530e4
Signed by: steffo
GPG key ID: 6965406171929D01
28 changed files with 180 additions and 121 deletions

View file

@ -5,6 +5,7 @@ import GlobalTheme from "./components/providers/GlobalTheme"
import GlobalServer from "./components/providers/GlobalServer"
import GlobalUser from "./components/providers/GlobalUser"
import PageSwitcher from "./PageSwitcher"
import GlobalLanguage from "./components/providers/GlobalLanguage"
/**
@ -15,16 +16,18 @@ import PageSwitcher from "./PageSwitcher"
*/
export default function App() {
return (
<GlobalServer>
<GlobalUser>
<GlobalTheme>
<BrowserRouter>
<Layout>
<PageSwitcher/>
</Layout>
</BrowserRouter>
</GlobalTheme>
</GlobalUser>
</GlobalServer>
<GlobalLanguage>
<GlobalServer>
<GlobalUser>
<GlobalTheme>
<BrowserRouter>
<Layout>
<PageSwitcher/>
</Layout>
</BrowserRouter>
</GlobalTheme>
</GlobalUser>
</GlobalServer>
</GlobalLanguage>
)
}

View file

@ -1,6 +1,3 @@
import LocalizedStrings from "react-localization"
/**
* All strings contained in the app should be present in this dict.
*
@ -12,7 +9,7 @@ import LocalizedStrings from "react-localization"
* "{number} km radius"
* ```
*/
export default new LocalizedStrings({
export default {
// 🇮🇹
it: {
appName: "N.E.S.T.",
@ -214,5 +211,4 @@ export default new LocalizedStrings({
admin: "Ylläpitäjä",
user: "Käyttäjä",
}
})
}

View file

@ -1,4 +1,4 @@
import React, { useState } from "react"
import React, { useContext, useState } from "react"
import BoxFull from "../base/BoxFull"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faClock, faPlus } from "@fortawesome/free-solid-svg-icons"
@ -10,7 +10,7 @@ import useRepositoryEditor from "../../hooks/useRepositoryEditor"
import ButtonToggleBeforeAfter from "./ButtonToggleBeforeAfter"
import Condition from "../../utils/Condition"
import convertToLocalISODate from "../../utils/convertToLocalISODate"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
const INVALID_USER_CHARACTERS = /[^0-9TZ:+-]/g
@ -28,6 +28,7 @@ export default function BoxConditionDatetime({ ...props }) {
const [datetime, setDatetime] = useState("")
const [ba, setBa] = useState(false)
const { addCondition } = useRepositoryEditor()
const {strings} = useContext(ContextLanguage)
const onInputChange = event => {
let text = event.target.value
@ -54,11 +55,11 @@ export default function BoxConditionDatetime({ ...props }) {
<BoxFull
header={
<span>
{Localization.searchBy}
{strings.searchBy}
&nbsp;
<FontAwesomeIcon icon={faClock}/>
&nbsp;
{Localization.byTimePeriod}
{strings.byTimePeriod}
</span>
}
{...props}

View file

@ -1,4 +1,4 @@
import React, { useState } from "react"
import React, { useContext, useState } from "react"
import BoxFull from "../base/BoxFull"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faHashtag, faPlus } from "@fortawesome/free-solid-svg-icons"
@ -8,7 +8,7 @@ import Style from "./BoxConditionHashtag.module.css"
import ButtonIconOnly from "../base/ButtonIconOnly"
import useRepositoryEditor from "../../hooks/useRepositoryEditor"
import Condition from "../../utils/Condition"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
// Official hashtag regex from https://stackoverflow.com/a/22490853/4334568
// noinspection RegExpAnonymousGroup,LongLine
@ -26,6 +26,7 @@ const INVALID_HASHTAG_CHARACTERS = /([^a-z0-9_\u00c0-\u00d6\u00d8-\u00f6\u00f8-\
export default function BoxConditionHashtag({ ...props }) {
const [hashtag, setHashtag] = useState("")
const { addCondition } = useRepositoryEditor()
const {strings} = useContext(ContextLanguage)
const onInputChange = event => {
let text = event.target.value
@ -45,11 +46,11 @@ export default function BoxConditionHashtag({ ...props }) {
<BoxFull
header={
<span>
{Localization.searchBy}
{strings.searchBy}
&nbsp;
<FontAwesomeIcon icon={faHashtag}/>
&nbsp;
{Localization.byHashtag}
{strings.byHashtag}
</span>
}
{...props}

View file

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from "react"
import React, { useCallback, useContext, useEffect, useState } from "react"
import BoxFull from "../base/BoxFull"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faAt, faMapPin, faPlus } from "@fortawesome/free-solid-svg-icons"
@ -7,7 +7,7 @@ import ButtonIconOnly from "../base/ButtonIconOnly"
import { MapContainer, TileLayer } from "react-leaflet"
import useRepositoryEditor from "../../hooks/useRepositoryEditor"
import Condition from "../../utils/Condition"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
const STARTING_POSITION = { lat: 41.89309, lng: 12.48289 }
@ -54,6 +54,7 @@ export default function BoxConditionMap({ ...props }) {
const [zoom, setZoom] = useState(STARTING_ZOOM)
const [map, setMap] = useState(null)
const { addCondition } = useRepositoryEditor()
const {strings} = useContext(ContextLanguage)
const onMove = useCallback(
() => {
@ -101,11 +102,11 @@ export default function BoxConditionMap({ ...props }) {
<BoxFull
header={
<span>
{Localization.searchBy}
{strings.searchBy}
&nbsp;
<FontAwesomeIcon icon={faMapPin}/>
&nbsp;
{Localization.byZone}
{strings.byZone}
</span>
}
childrenClassName={Style.BoxConditionMapContents}

View file

@ -1,4 +1,4 @@
import React, { useState } from "react"
import React, { useContext, useState } from "react"
import BoxFull from "../base/BoxFull"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faAt, faPlus } from "@fortawesome/free-solid-svg-icons"
@ -8,7 +8,7 @@ import Style from "./BoxConditionUser.module.css"
import ButtonIconOnly from "../base/ButtonIconOnly"
import useRepositoryEditor from "../../hooks/useRepositoryEditor"
import Condition from "../../utils/Condition"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
const INVALID_USER_CHARACTERS = /[^a-zA-Z0-9]/g
@ -25,6 +25,7 @@ const INVALID_USER_CHARACTERS = /[^a-zA-Z0-9]/g
export default function BoxConditionUser({ ...props }) {
const [user, setUser] = useState("")
const { addCondition } = useRepositoryEditor()
const {strings} = useContext(ContextLanguage)
const onInputChange = event => {
let text = event.target.value
@ -44,11 +45,11 @@ export default function BoxConditionUser({ ...props }) {
<BoxFull
header={
<span>
{Localization.searchBy}
{strings.searchBy}
&nbsp;
<FontAwesomeIcon icon={faAt}/>
&nbsp;
{Localization.byUser}
{strings.byUser}
</span>
}
{...props}

View file

@ -1,8 +1,8 @@
import React from "react"
import React, { useContext } from "react"
import BoxFull from "../base/BoxFull"
import ConditionBadge from "./ConditionBadge"
import useRepositoryEditor from "../../hooks/useRepositoryEditor"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -14,11 +14,12 @@ import Localization from "../../Localization"
*/
export default function BoxConditions({ ...props }) {
const { conditions } = useRepositoryEditor()
const {strings} = useContext(ContextLanguage)
const badges = conditions.map((cond, pos) => <ConditionBadge key={pos} {...cond}/>)
return (
<BoxFull header={Localization.conditions} {...props}>
<BoxFull header={strings.conditions} {...props}>
{badges}
</BoxFull>
)

View file

@ -7,7 +7,7 @@ import ContextUser from "../../contexts/ContextUser"
import { useHistory } from "react-router"
import Style from "./BoxLoggedIn.module.css"
import CurrentServer from "./CurrentServer"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -20,12 +20,13 @@ import Localization from "../../Localization"
export default function BoxLoggedIn({ ...props }) {
const { logout } = useContext(ContextUser)
const history = useHistory()
const {strings} = useContext(ContextLanguage)
return (
<BoxFull header={Localization.loggedInTitle} {...props}>
<BoxFull header={strings.loggedInTitle} {...props}>
<div className={Style.BoxLoggedInContents}>
<div>
{Localization.loggedInOn} <CurrentServer/> {Localization.loggedInAs} <LoggedInUser/>.
{strings.loggedInOn} <CurrentServer/> {strings.loggedInAs} <LoggedInUser/>.
</div>
<div>
<Button
@ -33,7 +34,7 @@ export default function BoxLoggedIn({ ...props }) {
logout()
history.push("/login")
}} icon={faSignOutAlt}
>{Localization.logout}</Button>
>{strings.logout}</Button>
</div>
</div>
</BoxFull>

View file

@ -8,7 +8,7 @@ import FormButton from "../base/formparts/FormButton"
import ContextUser from "../../contexts/ContextUser"
import { useHistory } from "react-router"
import FormAlert from "../base/formparts/FormAlert"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -25,6 +25,7 @@ export default function BoxLogin({ ...props }) {
const [error, setError] = useState(null)
const { login } = useContext(ContextUser)
const history = useHistory()
const {strings} = useContext(ContextLanguage)
const doLogin = async () => {
if(working) {
@ -45,9 +46,9 @@ export default function BoxLogin({ ...props }) {
}
return (
<BoxFull header={Localization.login} {...props}>
<BoxFull header={strings.login} {...props}>
<FormLabelled>
<FormLabel text={Localization.email} htmlFor={"login-email"}>
<FormLabel text={strings.email} htmlFor={"login-email"}>
<InputWithIcon
id={"login-email"}
name={"login-email"}
@ -57,7 +58,7 @@ export default function BoxLogin({ ...props }) {
icon={faEnvelope}
/>
</FormLabel>
<FormLabel text={Localization.passwd} htmlFor={"login-password"}>
<FormLabel text={strings.passwd} htmlFor={"login-password"}>
<InputWithIcon
id={"login-password"}
name={"login-password"}
@ -78,7 +79,7 @@ export default function BoxLogin({ ...props }) {
color={"Green"}
disabled={working}
>
{Localization.login}
{strings.login}
</FormButton>
</FormLabelled>
</BoxFull>

View file

@ -4,7 +4,7 @@ import { faFolderOpen } from "@fortawesome/free-solid-svg-icons"
import ContextUser from "../../contexts/ContextUser"
import Loading from "../base/Loading"
import BoxFullScrollable from "../base/BoxFullScrollable"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
* A {@link BoxFull} listing all the user's active repositories.
@ -25,13 +25,14 @@ export default function BoxRepositoriesActive({
...props
}) {
const { user } = useContext(ContextUser)
const {strings} = useContext(ContextLanguage)
let contents
if(repositories === null) {
contents = <Loading/>
}
else if(repositories.length === 0) {
contents = <i>{Localization.emptyMenu}.</i>
contents = <i>{strings.emptyMenu}.</i>
}
else {
contents = repositories.map(repo => (
@ -50,7 +51,7 @@ export default function BoxRepositoriesActive({
}
return (
<BoxFullScrollable header={Localization.menuActive} {...props}>
<BoxFullScrollable header={strings.menuActive} {...props}>
{contents}
</BoxFullScrollable>
)

View file

@ -4,7 +4,7 @@ import { faFolderOpen } from "@fortawesome/free-solid-svg-icons"
import ContextUser from "../../contexts/ContextUser"
import Loading from "../base/Loading"
import BoxFullScrollable from "../base/BoxFullScrollable"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -26,13 +26,14 @@ export default function BoxRepositoriesArchived({
...props
}) {
const { user } = useContext(ContextUser)
const {strings} = useContext(ContextLanguage)
let contents
if(repositories === null) {
contents = <Loading/>
}
else if(repositories.length === 0) {
contents = <i>{Localization.emptyMenu}.</i>
contents = <i>{strings.emptyMenu}.</i>
}
else {
contents = repositories.map(repo => (
@ -51,7 +52,7 @@ export default function BoxRepositoriesArchived({
}
return (
<BoxFullScrollable header={Localization.menuArchived} {...props}>
<BoxFullScrollable header={strings.menuArchived} {...props}>
{contents}
</BoxFullScrollable>
)

View file

@ -1,4 +1,4 @@
import React from "react"
import React, { useContext } from "react"
import BoxFull from "../base/BoxFull"
import FormLabelled from "../base/FormLabelled"
import FormLabel from "../base/formparts/FormLabel"
@ -10,7 +10,7 @@ import useRepositoryEditor from "../../hooks/useRepositoryEditor"
import FormAlert from "../base/formparts/FormAlert"
import goToOnSuccess from "../../utils/goToOnSuccess"
import { useHistory } from "react-router"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -34,16 +34,17 @@ export default function BoxRepositoryCreate({ running, ...props }) {
} = useRepositoryEditor()
const history = useHistory()
const {strings} = useContext(ContextLanguage)
return (
<BoxFull header={Localization.createRepo} {...props}>
<BoxFull header={strings.createRepo} {...props}>
<FormLabelled
onSubmit={e => {
e.preventDefault()
save()
}}
>
<FormLabel htmlFor={"repo-name"} text={Localization.repoName}>
<FormLabel htmlFor={"repo-name"} text={strings.repoName}>
<InputWithIcon
id={"repo-name"}
icon={faFolder}
@ -51,14 +52,14 @@ export default function BoxRepositoryCreate({ running, ...props }) {
onChange={e => setName(e.target.value)}
/>
</FormLabel>
<FormLabel htmlFor={"filter-mode"} text={Localization.request}>
<FormLabel htmlFor={"filter-mode"} text={strings.request}>
<label>
<Radio
name={"filter-mode"}
onChange={() => setEvaluationMode(0)}
checked={evaluationMode === 0}
/>
{Localization.filterOR}
{strings.filterOR}
</label>
&nbsp;
<label>
@ -67,7 +68,7 @@ export default function BoxRepositoryCreate({ running, ...props }) {
onChange={() => setEvaluationMode(1)}
checked={evaluationMode === 1}
/>
{Localization.filterAND}
{strings.filterAND}
</label>
</FormLabel>
{error ?
@ -84,7 +85,7 @@ export default function BoxRepositoryCreate({ running, ...props }) {
onClick={() => revert()}
disabled={running}
>
{Localization.rollback}
{strings.rollback}
</Button>
<Button
style={{ "gridColumn": "2" }}
@ -93,7 +94,7 @@ export default function BoxRepositoryCreate({ running, ...props }) {
onClick={_ => goToOnSuccess(save, history, "/repositories")()}
disabled={running}
>
{Localization.save}
{strings.save}
</Button>
</>
:
@ -104,7 +105,7 @@ export default function BoxRepositoryCreate({ running, ...props }) {
onClick={_ => goToOnSuccess(save, history, "/repositories")()}
disabled={running}
>
{Localization.createRepo}
{strings.createRepo}
</Button>
}

View file

@ -5,7 +5,7 @@ import FormLabel from "../base/formparts/FormLabel"
import InputWithIcon from "../base/InputWithIcon"
import { faGlobe } from "@fortawesome/free-solid-svg-icons"
import ContextServer from "../../contexts/ContextServer"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -17,11 +17,12 @@ import Localization from "../../Localization"
*/
export default function BoxSetServer({ ...props }) {
const { server, setServer } = useContext(ContextServer)
const {strings} = useContext(ContextLanguage)
return (
<BoxFull header={Localization.server} {...props}>
<BoxFull header={strings.server} {...props}>
<FormLabelled>
<FormLabel text={Localization.baseURL} htmlFor={"set-server-base-url"}>
<FormLabel text={strings.baseURL} htmlFor={"set-server-base-url"}>
<InputWithIcon
id={"set-server-base-url"}
type={"url"}

View file

@ -1,4 +1,4 @@
import React, { useCallback, useState } from "react"
import React, { useCallback, useContext, useState } from "react"
import FormLabelled from "../base/FormLabelled"
import FormLabel from "../base/formparts/FormLabel"
import InputWithIcon from "../base/InputWithIcon"
@ -6,7 +6,7 @@ import { faEnvelope, faKey, faPlus, faUser } from "@fortawesome/free-solid-svg-i
import FormButton from "../base/formparts/FormButton"
import BoxFull from "../base/BoxFull"
import FormAlert from "../base/formparts/FormAlert"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
export default function BoxUserCreate({ createUser, running, ...props }) {
@ -14,6 +14,7 @@ export default function BoxUserCreate({ createUser, running, ...props }) {
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [error, setError] = useState(undefined)
const {strings} = useContext(ContextLanguage)
const onButtonClick = useCallback(
async () => {
@ -28,9 +29,9 @@ export default function BoxUserCreate({ createUser, running, ...props }) {
)
return (
<BoxFull header={Localization.userCreate} {...props}>
<BoxFull header={strings.userCreate} {...props}>
<FormLabelled>
<FormLabel text={Localization.userName}>
<FormLabel text={strings.userName}>
<InputWithIcon
icon={faUser}
type={"text"}
@ -38,7 +39,7 @@ export default function BoxUserCreate({ createUser, running, ...props }) {
onChange={event => setUsername(event.target.value)}
/>
</FormLabel>
<FormLabel text={Localization.email}>
<FormLabel text={strings.email}>
<InputWithIcon
icon={faEnvelope}
type={"text"}
@ -46,7 +47,7 @@ export default function BoxUserCreate({ createUser, running, ...props }) {
onChange={event => setEmail(event.target.value)}
/>
</FormLabel>
<FormLabel text={Localization.passwd}>
<FormLabel text={strings.passwd}>
<InputWithIcon
icon={faKey}
type={"password"}
@ -65,7 +66,7 @@ export default function BoxUserCreate({ createUser, running, ...props }) {
onClick={onButtonClick}
disabled={running}
>
{Localization.create}
{strings.create}
</FormButton>
</FormLabelled>
</BoxFull>

View file

@ -1,11 +1,13 @@
import React from "react"
import React, { useContext } from "react"
import Loading from "../base/Loading"
import BoxFullScrollable from "../base/BoxFullScrollable"
import SummaryUser from "./SummaryUser"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
export default function BoxUserList({ users, destroyUser, running, ...props }) {
const {strings} = useContext(ContextLanguage)
let contents
if(users === null) {
contents = <Loading/>
@ -16,7 +18,7 @@ export default function BoxUserList({ users, destroyUser, running, ...props }) {
}
return (
<BoxFullScrollable header={Localization.userList} {...props}>
<BoxFullScrollable header={strings.userList} {...props}>
{contents}
</BoxFullScrollable>
)

View file

@ -1,7 +1,7 @@
import React from "react"
import React, { useContext } from "react"
import BoxFull from "../base/BoxFull"
import ReactWordcloud from "@steffo/nest-react-wordcloud"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -13,8 +13,10 @@ import Localization from "../../Localization"
* @constructor
*/
export default function BoxWordcloud({ words, props }) {
const {strings} = useContext(ContextLanguage)
return (
<BoxFull header={Localization.wordcloud} {...props}>
<BoxFull header={strings.wordcloud} {...props}>
<div style={{"width": "100%", "height": "100%"}}>
<ReactWordcloud
options={{

View file

@ -1,12 +1,13 @@
import React, { useState } from "react"
import React, { useContext, useState } from "react"
import Style from "./ButtonToggleBeforeAfter.module.css"
import classNames from "classnames"
import Button from "../base/Button"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
export default function ButtonToggleBeforeAfter({ onUpdate, className, ...props }) {
const [value, setValue] = useState(false)
const {strings} = useContext(ContextLanguage)
const onButtonClick = () => {
onUpdate(!value)
@ -20,7 +21,7 @@ export default function ButtonToggleBeforeAfter({ onUpdate, className, ...props
onClick={onButtonClick}
{...props}
>
{value ? Localization.timeBefore : Localization.timeAfter}
{value ? strings.timeBefore : strings.timeAfter}
</Button>
)
}

View file

@ -2,7 +2,7 @@ import React, { useContext } from "react"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faUser } from "@fortawesome/free-solid-svg-icons"
import ContextUser from "../../contexts/ContextUser"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -14,11 +14,12 @@ import Localization from "../../Localization"
*/
export default function LoggedInUser({ ...props }) {
const { user } = useContext(ContextUser)
const {strings} = useContext(ContextLanguage)
if(!user) {
return (
<i {...props}>
{Localization.notLoggedIn}
{strings.notLoggedIn}
</i>
)
}

View file

@ -4,7 +4,7 @@ import LogoDark from "../../media/LogoDark.png"
import LogoLight from "../../media/LogoLight.png"
import ContextTheme from "../../contexts/ContextTheme"
import classNames from "classnames"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -18,9 +18,8 @@ import Localization from "../../Localization"
* @constructor
*/
export default function Logo({ className, ...props }) {
// I have no idea why IntelliJ is complaining about this line
// It's perfectly fine!
const { theme } = useContext(ContextTheme)
const {strings} = useContext(ContextLanguage)
let logo
if(theme === "ThemeDark") {
@ -37,8 +36,8 @@ export default function Logo({ className, ...props }) {
<img
src={logo}
className={classNames(Style.Logo, className)}
alt={Localization.appName}
title={Localization.appFullName}
alt={strings.appName}
title={strings.appFullName}
{...props}
/>
)

View file

@ -1,6 +1,6 @@
import React, { useState } from "react"
import React, { useContext } from "react"
import Select from "../base/Select"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -12,17 +12,10 @@ import Localization from "../../Localization"
* @constructor
*/
export default function SelectLanguage({ ...props }) {
const [_language, _setLanguage] = useState(Localization.getLanguage())
const setLanguage = event => {
const language = event.target.value
console.info("Changing language to: ", language)
Localization.setLanguage(language)
_setLanguage(language)
}
const {strings, lang, setLang} = useContext(ContextLanguage)
return (
<Select value={_language} onChange={setLanguage} {...props}>
<Select value={lang} onChange={event => setLang(event.target.value)} {...props}>
<option value={"it"}>🇮🇹 Italiano</option>
<option value={"en"}>🇬🇧 English</option>
<option value={"fi"}>🇫🇮 Suomi</option>

View file

@ -1,7 +1,7 @@
import React, { useContext } from "react"
import Select from "../base/Select"
import ContextTheme from "../../contexts/ContextTheme"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -14,11 +14,12 @@ import Localization from "../../Localization"
*/
export default function SelectTheme({ ...props }) {
const { theme, setTheme } = useContext(ContextTheme)
const {strings} = useContext(ContextLanguage)
return (
<Select value={theme} onChange={e => setTheme(e.target.value)} {...props}>
<option value={"ThemeDark"}>{Localization.darkMode}</option>
<option value={"ThemeLight"}>{Localization.lightMode}</option>
<option value={"ThemeDark"}>{strings.darkMode}</option>
<option value={"ThemeLight"}>{strings.lightMode}</option>
</Select>
)
}

View file

@ -12,7 +12,7 @@ import {
faUserCog,
} from "@fortawesome/free-solid-svg-icons"
import ContextUser from "../../contexts/ContextUser"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -26,6 +26,7 @@ import Localization from "../../Localization"
*/
export default function Sidebar({ className, ...props }) {
const { user } = useContext(ContextUser)
const {strings} = useContext(ContextLanguage)
return (
<aside className={classNames(Style.Sidebar, className)} {...props}>
@ -33,20 +34,20 @@ export default function Sidebar({ className, ...props }) {
{
user ?
<>
<ButtonSidebar to={"/dashboard"} icon={faHome}>{Localization.dashboard}</ButtonSidebar>
<ButtonSidebar to={"/repositories"} icon={faFolder}>{Localization.repositories}</ButtonSidebar>
<ButtonSidebar to={"/alerts"} icon={faExclamationTriangle}>{Localization.alerts}</ButtonSidebar>
<ButtonSidebar to={"/settings"} icon={faCog}>{Localization.settings}</ButtonSidebar>
<ButtonSidebar to={"/dashboard"} icon={faHome}>{strings.dashboard}</ButtonSidebar>
<ButtonSidebar to={"/repositories"} icon={faFolder}>{strings.repositories}</ButtonSidebar>
<ButtonSidebar to={"/alerts"} icon={faExclamationTriangle}>{strings.alerts}</ButtonSidebar>
<ButtonSidebar to={"/settings"} icon={faCog}>{strings.settings}</ButtonSidebar>
</>
:
<>
<ButtonSidebar to={"/login"} icon={faKey}>{Localization.login}</ButtonSidebar>
<ButtonSidebar to={"/login"} icon={faKey}>{strings.login}</ButtonSidebar>
</>
}
{
user && user.isAdmin ?
<>
<ButtonSidebar to={"/users"} icon={faUserCog}>{Localization.users}</ButtonSidebar>
<ButtonSidebar to={"/users"} icon={faUserCog}>{strings.users}</ButtonSidebar>
</>
:
null

View file

@ -1,9 +1,9 @@
import React from "react"
import React, { useContext } from "react"
import Button from "../base/Button"
import { faArchive, faFolder, faFolderOpen, faPencilAlt, faTrash } from "@fortawesome/free-solid-svg-icons"
import { useHistory } from "react-router"
import Summary from "../base/Summary"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
/**
@ -26,6 +26,7 @@ export default function SummaryRepository(
{ repo, refresh, canDelete, deleteSelf, canEdit, canArchive, archiveSelf, running, className, ...props },
) {
const history = useHistory()
const {strings} = useContext(ContextLanguage)
const onRepoClick = () => {
history.push(`/repositories/${repo.id}`)
@ -43,7 +44,7 @@ export default function SummaryRepository(
onClick={deleteSelf}
disabled={running}
>
{Localization.delete}
{strings.delete}
</Button>
: null}
{canEdit ?
@ -53,7 +54,7 @@ export default function SummaryRepository(
onClick={onEditClick}
disabled={running}
>
{Localization.Edit}
{strings.edit}
</Button>
: null}
{canArchive ?
@ -63,7 +64,7 @@ export default function SummaryRepository(
onClick={archiveSelf}
disabled={running}
>
{Localization.achive}
{strings.archive}
</Button>
: null}
</>
@ -74,9 +75,9 @@ export default function SummaryRepository(
title={repo.name}
subtitle={repo.owner ? repo.owner.username : null}
onClick={onRepoClick}
upperLabel={Localization.created}
upperLabel={strings.created}
upperValue={repo.start ? new Date(repo.start).toLocaleString() : null}
lowerLabel={Localization.archived}
lowerLabel={strings.archived}
lowerValue={repo.end ? new Date(repo.end).toLocaleString() : null}
buttons={buttons}
{...props}

View file

@ -3,11 +3,12 @@ import Summary from "../base/Summary"
import { faStar, faTrash, faUser } from "@fortawesome/free-solid-svg-icons"
import Button from "../base/Button"
import ContextUser from "../../contexts/ContextUser"
import Localization from "../../Localization"
import ContextLanguage from "../../contexts/ContextLanguage"
export default function SummaryUser({ user, destroyUser, running, ...props }) {
const { user: loggedUser } = useContext(ContextUser)
const {strings} = useContext(ContextLanguage)
const buttons = <>
{loggedUser.email !== user.email ?
@ -21,7 +22,7 @@ export default function SummaryUser({ user, destroyUser, running, ...props }) {
}}
disabled={running}
>
{Localization.delete}
{strings.delete}
</Button>
: null}
</>
@ -31,8 +32,8 @@ export default function SummaryUser({ user, destroyUser, running, ...props }) {
icon={user.isAdmin ? faStar : faUser}
title={user.username}
subtitle={user.email}
upperLabel={Localization.type}
upperValue={user.isAdmin ? Localization.admin : Localization.user}
upperLabel={strings.type}
upperValue={user.isAdmin ? strings.admin : strings.user}
buttons={buttons}
{...props}
/>

View file

@ -0,0 +1,26 @@
import React from "react"
import useLocalStorageState from "../../hooks/useLocalStorageState"
import ContextLanguage from "../../contexts/ContextLanguage"
import LocalizationStrings from "../../LocalizationStrings"
/**
* Provides {@link ContextLanguage} to all contained elements.
*
* Defaults to using Italian.
*
* @param children
* @returns {JSX.Element}
* @constructor
*/
export default function GlobalLanguage({ children }) {
const [lang, setLang] = useLocalStorageState("language", "it")
const strings = LocalizationStrings[lang]
return (
<ContextLanguage.Provider value={{ lang, setLang, strings }}>
{children}
</ContextLanguage.Provider>
)
}

View file

@ -0,0 +1,14 @@
import { createContext } from "react"
/**
* A context containing an object with the following values:
* - `lang`: a string corresponding to the ISO 639-1 code of the current language
* - `setLang`: a function to change the current language
* - `strings`: an object containing all strings of the current language
*/
export default createContext({
lang: null,
setLang: () => console.error("Trying to setLang while outside a ContextServer.Provider!"),
strings: null,
})

View file

@ -1,10 +1,13 @@
import React from "react"
import React, { useContext } from "react"
import Style from "./PageAlerts.module.css"
import classNames from "classnames"
import BoxFull from "../components/base/BoxFull"
import ContextLanguage from "../contexts/ContextLanguage"
export default function PageAlerts({ children, className, ...props }) {
const {strings} = useContext(ContextLanguage)
return (
<div className={classNames(Style.PageAlerts, className)} {...props}>
<BoxFull header={"I tuoi allarmi"} className={Style.YourAlerts}>

View file

@ -1,11 +1,14 @@
import React from "react"
import React, { useContext } from "react"
import Style from "./PageDashboard.module.css"
import classNames from "classnames"
import BoxHeader from "../components/base/BoxHeader"
import RepositoryEditor from "../components/providers/RepositoryEditor"
import ContextLanguage from "../contexts/ContextLanguage"
export default function PageDashboard({ children, className, ...props }) {
const {strings} = useContext(ContextLanguage)
return (
<div className={classNames(Style.PageHome, className)} {...props}>
<BoxHeader className={Style.Header}>