mirror of
https://github.com/pds-nest/nest.git
synced 2024-11-25 14:34:19 +00:00
✨ Use custom localization system
This commit is contained in:
parent
c0e87fb6ba
commit
20f60530e4
28 changed files with 180 additions and 121 deletions
|
@ -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,6 +16,7 @@ import PageSwitcher from "./PageSwitcher"
|
|||
*/
|
||||
export default function App() {
|
||||
return (
|
||||
<GlobalLanguage>
|
||||
<GlobalServer>
|
||||
<GlobalUser>
|
||||
<GlobalTheme>
|
||||
|
@ -26,5 +28,6 @@ export default function App() {
|
|||
</GlobalTheme>
|
||||
</GlobalUser>
|
||||
</GlobalServer>
|
||||
</GlobalLanguage>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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ä",
|
||||
}
|
||||
})
|
||||
|
||||
}
|
|
@ -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}
|
||||
|
||||
<FontAwesomeIcon icon={faClock}/>
|
||||
|
||||
{Localization.byTimePeriod}
|
||||
{strings.byTimePeriod}
|
||||
</span>
|
||||
}
|
||||
{...props}
|
||||
|
|
|
@ -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}
|
||||
|
||||
<FontAwesomeIcon icon={faHashtag}/>
|
||||
|
||||
{Localization.byHashtag}
|
||||
{strings.byHashtag}
|
||||
</span>
|
||||
}
|
||||
{...props}
|
||||
|
|
|
@ -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}
|
||||
|
||||
<FontAwesomeIcon icon={faMapPin}/>
|
||||
|
||||
{Localization.byZone}
|
||||
{strings.byZone}
|
||||
</span>
|
||||
}
|
||||
childrenClassName={Style.BoxConditionMapContents}
|
||||
|
|
|
@ -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}
|
||||
|
||||
<FontAwesomeIcon icon={faAt}/>
|
||||
|
||||
{Localization.byUser}
|
||||
{strings.byUser}
|
||||
</span>
|
||||
}
|
||||
{...props}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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>
|
||||
|
||||
<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>
|
||||
}
|
||||
|
||||
|
|
|
@ -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"}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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={{
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
|
|
26
nest_frontend/components/providers/GlobalLanguage.js
Normal file
26
nest_frontend/components/providers/GlobalLanguage.js
Normal 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>
|
||||
)
|
||||
}
|
14
nest_frontend/contexts/ContextLanguage.js
Normal file
14
nest_frontend/contexts/ContextLanguage.js
Normal 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,
|
||||
})
|
|
@ -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}>
|
||||
|
|
|
@ -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}>
|
||||
|
|
Loading…
Reference in a new issue